View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase;
19  
20  import javax.annotation.Nonnull;
21  import javax.annotation.Nullable;
22  import java.io.Closeable;
23  import java.io.IOException;
24  import java.io.InterruptedIOException;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.LinkedHashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.NavigableMap;
31  import java.util.Set;
32  import java.util.SortedMap;
33  import java.util.TreeMap;
34  import java.util.regex.Matcher;
35  import java.util.regex.Pattern;
36  
37  import com.google.common.annotations.VisibleForTesting;
38  import com.google.protobuf.ServiceException;
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  import org.apache.hadoop.conf.Configuration;
42  import org.apache.hadoop.hbase.classification.InterfaceAudience;
43  import org.apache.hadoop.hbase.client.Connection;
44  import org.apache.hadoop.hbase.client.ConnectionFactory;
45  import org.apache.hadoop.hbase.client.Consistency;
46  import org.apache.hadoop.hbase.client.Delete;
47  import org.apache.hadoop.hbase.client.Get;
48  import org.apache.hadoop.hbase.client.Mutation;
49  import org.apache.hadoop.hbase.client.Put;
50  import org.apache.hadoop.hbase.client.RegionLocator;
51  import org.apache.hadoop.hbase.client.RegionReplicaUtil;
52  import org.apache.hadoop.hbase.client.Result;
53  import org.apache.hadoop.hbase.client.ResultScanner;
54  import org.apache.hadoop.hbase.client.Scan;
55  import org.apache.hadoop.hbase.client.Table;
56  import org.apache.hadoop.hbase.client.TableState;
57  import org.apache.hadoop.hbase.exceptions.DeserializationException;
58  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
59  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
60  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
61  import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos;
62  import org.apache.hadoop.hbase.util.Bytes;
63  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
64  import org.apache.hadoop.hbase.util.ExceptionUtil;
65  import org.apache.hadoop.hbase.util.Pair;
66  import org.apache.hadoop.hbase.util.PairOfSameType;
67  
68  /**
69   * Read/write operations on region and assignment information store in
70   * <code>hbase:meta</code>.
71   *
72   * Some of the methods of this class take ZooKeeperWatcher as a param. The only reason
73   * for this is because when used on client-side (like from HBaseAdmin), we want to use
74   * short-living connection (opened before each operation, closed right after), while
75   * when used on HM or HRS (like in AssignmentManager) we want permanent connection.
76   */
77  @InterfaceAudience.Private
78  public class MetaTableAccessor {
79  
80    /*
81     * HBASE-10070 adds a replicaId to HRI, meaning more than one HRI can be defined for the
82     * same table range (table, startKey, endKey). For every range, there will be at least one
83     * HRI defined which is called default replica.
84     *
85     * Meta layout (as of 0.98 + HBASE-10070) is like:
86     *
87     * For each table there is single row in column family 'table' formatted:
88     * <tableName> including namespace and columns are:
89     * table: state             => contains table state
90     *
91     * For each table range, there is a single row, formatted like:
92     * <tableName>,<startKey>,<regionId>,<encodedRegionName>. This row corresponds to the regionName
93     * of the default region replica.
94     * Columns are:
95     * info:regioninfo         => contains serialized HRI for the default region replica
96     * info:server             => contains hostname:port (in string form) for the server hosting
97     *                            the default regionInfo replica
98     * info:server_<replicaId> => contains hostname:port (in string form) for the server hosting the
99     *                            regionInfo replica with replicaId
100    * info:serverstartcode    => contains server start code (in binary long form) for the server
101    *                            hosting the default regionInfo replica
102    * info:serverstartcode_<replicaId> => contains server start code (in binary long form) for the
103    *                                     server hosting the regionInfo replica with replicaId
104    * info:seqnumDuringOpen    => contains seqNum (in binary long form) for the region at the time
105    *                             the server opened the region with default replicaId
106    * info:seqnumDuringOpen_<replicaId> => contains seqNum (in binary long form) for the region at
107    *                             the time the server opened the region with replicaId
108    * info:splitA              => contains a serialized HRI for the first daughter region if the
109    *                             region is split
110    * info:splitB              => contains a serialized HRI for the second daughter region if the
111    *                             region is split
112    * info:mergeA              => contains a serialized HRI for the first parent region if the
113    *                             region is the result of a merge
114    * info:mergeB              => contains a serialized HRI for the second parent region if the
115    *                             region is the result of a merge
116    *
117    * The actual layout of meta should be encapsulated inside MetaTableAccessor methods,
118    * and should not leak out of it (through Result objects, etc)
119    */
120 
121   private static final Log LOG = LogFactory.getLog(MetaTableAccessor.class);
122   private static final Log METALOG = LogFactory.getLog("org.apache.hadoop.hbase.META");
123 
124   static final byte [] META_REGION_PREFIX;
125   static {
126     // Copy the prefix from FIRST_META_REGIONINFO into META_REGION_PREFIX.
127     // FIRST_META_REGIONINFO == 'hbase:meta,,1'.  META_REGION_PREFIX == 'hbase:meta,'
128     int len = HRegionInfo.FIRST_META_REGIONINFO.getRegionName().length - 2;
129     META_REGION_PREFIX = new byte [len];
130     System.arraycopy(HRegionInfo.FIRST_META_REGIONINFO.getRegionName(), 0,
131       META_REGION_PREFIX, 0, len);
132   }
133 
134   /**
135    * Lists all of the table regions currently in META.
136    * Deprecated, keep there until some test use this.
137    * @param connection what we will use
138    * @param tableName table to list
139    * @return Map of all user-space regions to servers
140    * @throws java.io.IOException
141    * @deprecated use {@link #getTableRegionsAndLocations}, region can have multiple locations
142    */
143   @Deprecated
144   public static NavigableMap<HRegionInfo, ServerName> allTableRegions(
145       Connection connection, final TableName tableName) throws IOException {
146     final NavigableMap<HRegionInfo, ServerName> regions =
147       new TreeMap<HRegionInfo, ServerName>();
148     Visitor visitor = new TableVisitorBase(tableName) {
149       @Override
150       public boolean visitInternal(Result result) throws IOException {
151         RegionLocations locations = getRegionLocations(result);
152         if (locations == null) return true;
153         for (HRegionLocation loc : locations.getRegionLocations()) {
154           if (loc != null) {
155             HRegionInfo regionInfo = loc.getRegionInfo();
156             regions.put(regionInfo, loc.getServerName());
157           }
158         }
159         return true;
160       }
161     };
162     scanMetaForTableRegions(connection, visitor, tableName);
163     return regions;
164   }
165 
166   @InterfaceAudience.Private
167   public enum QueryType {
168     ALL(HConstants.TABLE_FAMILY, HConstants.CATALOG_FAMILY),
169     REGION(HConstants.CATALOG_FAMILY),
170     TABLE(HConstants.TABLE_FAMILY);
171 
172     private final byte[][] families;
173 
174     QueryType(byte[]... families) {
175       this.families = families;
176     }
177 
178     byte[][] getFamilies() {
179       return this.families;
180     }
181   }
182 
183   /** The delimiter for meta columns for replicaIds &gt; 0 */
184   protected static final char META_REPLICA_ID_DELIMITER = '_';
185 
186   /** A regex for parsing server columns from meta. See above javadoc for meta layout */
187   private static final Pattern SERVER_COLUMN_PATTERN
188     = Pattern.compile("^server(_[0-9a-fA-F]{4})?$");
189 
190   ////////////////////////
191   // Reading operations //
192   ////////////////////////
193 
194   /**
195    * Performs a full scan of <code>hbase:meta</code> for regions.
196    * @param connection connection we're using
197    * @param visitor Visitor invoked against each row in regions family.
198    * @throws IOException
199    */
200   public static void fullScanRegions(Connection connection,
201       final Visitor visitor)
202       throws IOException {
203     scanMeta(connection, null, null, QueryType.REGION, visitor);
204   }
205 
206   /**
207    * Performs a full scan of <code>hbase:meta</code> for regions.
208    * @param connection connection we're using
209    * @throws IOException
210    */
211   public static List<Result> fullScanRegions(Connection connection)
212       throws IOException {
213     return fullScan(connection, QueryType.REGION);
214   }
215 
216   /**
217    * Performs a full scan of <code>hbase:meta</code> for tables.
218    * @param connection connection we're using
219    * @param visitor Visitor invoked against each row in tables family.
220    * @throws IOException
221    */
222   public static void fullScanTables(Connection connection,
223       final Visitor visitor)
224       throws IOException {
225     scanMeta(connection, null, null, QueryType.TABLE, visitor);
226   }
227 
228   /**
229    * Performs a full scan of <code>hbase:meta</code>.
230    * @param connection connection we're using
231    * @param type scanned part of meta
232    * @return List of {@link Result}
233    * @throws IOException
234    */
235   public static List<Result> fullScan(Connection connection, QueryType type)
236     throws IOException {
237     CollectAllVisitor v = new CollectAllVisitor();
238     scanMeta(connection, null, null, type, v);
239     return v.getResults();
240   }
241 
242   /**
243    * Callers should call close on the returned {@link Table} instance.
244    * @param connection connection we're using to access Meta
245    * @return An {@link Table} for <code>hbase:meta</code>
246    * @throws IOException
247    */
248   static Table getMetaHTable(final Connection connection)
249   throws IOException {
250     // We used to pass whole CatalogTracker in here, now we just pass in Connection
251     if (connection == null) {
252       throw new NullPointerException("No connection");
253     } else if (connection.isClosed()) {
254       throw new IOException("connection is closed");
255     }
256     return connection.getTable(TableName.META_TABLE_NAME);
257   }
258 
259   /**
260    * @param t Table to use (will be closed when done).
261    * @param g Get to run
262    * @throws IOException
263    */
264   private static Result get(final Table t, final Get g) throws IOException {
265     if (t == null) return null;
266     try {
267       return t.get(g);
268     } finally {
269       t.close();
270     }
271   }
272 
273   /**
274    * Gets the region info and assignment for the specified region.
275    * @param connection connection we're using
276    * @param regionName Region to lookup.
277    * @return Location and HRegionInfo for <code>regionName</code>
278    * @throws IOException
279    * @deprecated use {@link #getRegionLocation(Connection, byte[])} instead
280    */
281   @Deprecated
282   public static Pair<HRegionInfo, ServerName> getRegion(Connection connection, byte [] regionName)
283     throws IOException {
284     HRegionLocation location = getRegionLocation(connection, regionName);
285     return location == null
286       ? null
287       : new Pair<HRegionInfo, ServerName>(location.getRegionInfo(), location.getServerName());
288   }
289 
290   /**
291    * Returns the HRegionLocation from meta for the given region
292    * @param connection connection we're using
293    * @param regionName region we're looking for
294    * @return HRegionLocation for the given region
295    * @throws IOException
296    */
297   public static HRegionLocation getRegionLocation(Connection connection,
298                                                   byte[] regionName) throws IOException {
299     byte[] row = regionName;
300     HRegionInfo parsedInfo = null;
301     try {
302       parsedInfo = parseRegionInfoFromRegionName(regionName);
303       row = getMetaKeyForRegion(parsedInfo);
304     } catch (Exception parseEx) {
305       // Ignore. This is used with tableName passed as regionName.
306     }
307     Get get = new Get(row);
308     get.addFamily(HConstants.CATALOG_FAMILY);
309     Result r = get(getMetaHTable(connection), get);
310     RegionLocations locations = getRegionLocations(r);
311     return locations == null
312       ? null
313       : locations.getRegionLocation(parsedInfo == null ? 0 : parsedInfo.getReplicaId());
314   }
315 
316   /**
317    * Returns the HRegionLocation from meta for the given region
318    * @param connection connection we're using
319    * @param regionInfo region information
320    * @return HRegionLocation for the given region
321    * @throws IOException
322    */
323   public static HRegionLocation getRegionLocation(Connection connection,
324                                                   HRegionInfo regionInfo) throws IOException {
325     byte[] row = getMetaKeyForRegion(regionInfo);
326     Get get = new Get(row);
327     get.addFamily(HConstants.CATALOG_FAMILY);
328     Result r = get(getMetaHTable(connection), get);
329     return getRegionLocation(r, regionInfo, regionInfo.getReplicaId());
330   }
331 
332   /** Returns the row key to use for this regionInfo */
333   public static byte[] getMetaKeyForRegion(HRegionInfo regionInfo) {
334     return RegionReplicaUtil.getRegionInfoForDefaultReplica(regionInfo).getRegionName();
335   }
336 
337   /** Returns an HRI parsed from this regionName. Not all the fields of the HRI
338    * is stored in the name, so the returned object should only be used for the fields
339    * in the regionName.
340    */
341   protected static HRegionInfo parseRegionInfoFromRegionName(byte[] regionName)
342     throws IOException {
343     byte[][] fields = HRegionInfo.parseRegionName(regionName);
344     long regionId =  Long.parseLong(Bytes.toString(fields[2]));
345     int replicaId = fields.length > 3 ? Integer.parseInt(Bytes.toString(fields[3]), 16) : 0;
346     return new HRegionInfo(
347       TableName.valueOf(fields[0]), fields[1], fields[1], false, regionId, replicaId);
348   }
349 
350   /**
351    * Gets the result in hbase:meta for the specified region.
352    * @param connection connection we're using
353    * @param regionName region we're looking for
354    * @return result of the specified region
355    * @throws IOException
356    */
357   public static Result getRegionResult(Connection connection,
358       byte[] regionName) throws IOException {
359     Get get = new Get(regionName);
360     get.addFamily(HConstants.CATALOG_FAMILY);
361     return get(getMetaHTable(connection), get);
362   }
363 
364   /**
365    * Get regions from the merge qualifier of the specified merged region
366    * @return null if it doesn't contain merge qualifier, else two merge regions
367    * @throws IOException
368    */
369   @Nullable
370   public static Pair<HRegionInfo, HRegionInfo> getRegionsFromMergeQualifier(
371       Connection connection, byte[] regionName) throws IOException {
372     Result result = getRegionResult(connection, regionName);
373     HRegionInfo mergeA = getHRegionInfo(result, HConstants.MERGEA_QUALIFIER);
374     HRegionInfo mergeB = getHRegionInfo(result, HConstants.MERGEB_QUALIFIER);
375     if (mergeA == null && mergeB == null) {
376       return null;
377     }
378     return new Pair<HRegionInfo, HRegionInfo>(mergeA, mergeB);
379  }
380 
381   /**
382    * Checks if the specified table exists.  Looks at the hbase:meta table hosted on
383    * the specified server.
384    * @param connection connection we're using
385    * @param tableName table to check
386    * @return true if the table exists in meta, false if not
387    * @throws IOException
388    */
389   public static boolean tableExists(Connection connection,
390       final TableName tableName)
391   throws IOException {
392     // Catalog tables always exist.
393     return tableName.equals(TableName.META_TABLE_NAME)
394         || getTableState(connection, tableName) != null;
395   }
396 
397   /**
398    * Lists all of the regions currently in META.
399    *
400    * @param connection to connect with
401    * @param excludeOfflinedSplitParents False if we are to include offlined/splitparents regions,
402    *                                    true and we'll leave out offlined regions from returned list
403    * @return List of all user-space regions.
404    * @throws IOException
405    */
406   @VisibleForTesting
407   public static List<HRegionInfo> getAllRegions(Connection connection,
408       boolean excludeOfflinedSplitParents)
409       throws IOException {
410     List<Pair<HRegionInfo, ServerName>> result;
411 
412     result = getTableRegionsAndLocations(connection, null,
413         excludeOfflinedSplitParents);
414 
415     return getListOfHRegionInfos(result);
416 
417   }
418 
419   /**
420    * Gets all of the regions of the specified table. Do not use this method
421    * to get meta table regions, use methods in MetaTableLocator instead.
422    * @param connection connection we're using
423    * @param tableName table we're looking for
424    * @return Ordered list of {@link HRegionInfo}.
425    * @throws IOException
426    */
427   public static List<HRegionInfo> getTableRegions(Connection connection, TableName tableName)
428   throws IOException {
429     return getTableRegions(connection, tableName, false);
430   }
431 
432   /**
433    * Gets all of the regions of the specified table. Do not use this method
434    * to get meta table regions, use methods in MetaTableLocator instead.
435    * @param connection connection we're using
436    * @param tableName table we're looking for
437    * @param excludeOfflinedSplitParents If true, do not include offlined split
438    * parents in the return.
439    * @return Ordered list of {@link HRegionInfo}.
440    * @throws IOException
441    */
442   public static List<HRegionInfo> getTableRegions(Connection connection,
443       TableName tableName, final boolean excludeOfflinedSplitParents)
444       throws IOException {
445     List<Pair<HRegionInfo, ServerName>> result;
446 
447     result = getTableRegionsAndLocations(connection, tableName,
448       excludeOfflinedSplitParents);
449 
450     return getListOfHRegionInfos(result);
451   }
452 
453   @Nullable
454   static List<HRegionInfo> getListOfHRegionInfos(final List<Pair<HRegionInfo, ServerName>> pairs) {
455     if (pairs == null || pairs.isEmpty()) return null;
456     List<HRegionInfo> result = new ArrayList<HRegionInfo>(pairs.size());
457     for (Pair<HRegionInfo, ServerName> pair: pairs) {
458       result.add(pair.getFirst());
459     }
460     return result;
461   }
462 
463   /**
464    * @param current region of current table we're working with
465    * @param tableName table we're checking against
466    * @return True if <code>current</code> tablename is equal to
467    * <code>tableName</code>
468    */
469   static boolean isInsideTable(final HRegionInfo current, final TableName tableName) {
470     return tableName.equals(current.getTable());
471   }
472 
473   /**
474    * @param tableName table we're working with
475    * @return start row for scanning META according to query type
476    */
477   public static byte[] getTableStartRowForMeta(TableName tableName, QueryType type) {
478     if (tableName == null) {
479       return null;
480     }
481     switch (type) {
482     case REGION:
483       byte[] startRow = new byte[tableName.getName().length + 2];
484       System.arraycopy(tableName.getName(), 0, startRow, 0, tableName.getName().length);
485       startRow[startRow.length - 2] = HConstants.DELIMITER;
486       startRow[startRow.length - 1] = HConstants.DELIMITER;
487       return startRow;
488     case ALL:
489     case TABLE:
490     default:
491       return tableName.getName();
492     }
493   }
494 
495   /**
496    * @param tableName table we're working with
497    * @return stop row for scanning META according to query type
498    */
499   public static byte[] getTableStopRowForMeta(TableName tableName, QueryType type) {
500     if (tableName == null) {
501       return null;
502     }
503     final byte[] stopRow;
504     switch (type) {
505     case REGION:
506       stopRow = new byte[tableName.getName().length + 3];
507       System.arraycopy(tableName.getName(), 0, stopRow, 0, tableName.getName().length);
508       stopRow[stopRow.length - 3] = ' ';
509       stopRow[stopRow.length - 2] = HConstants.DELIMITER;
510       stopRow[stopRow.length - 1] = HConstants.DELIMITER;
511       break;
512     case ALL:
513     case TABLE:
514     default:
515       stopRow = new byte[tableName.getName().length + 1];
516       System.arraycopy(tableName.getName(), 0, stopRow, 0, tableName.getName().length);
517       stopRow[stopRow.length - 1] = ' ';
518       break;
519     }
520     return stopRow;
521   }
522 
523   /**
524    * This method creates a Scan object that will only scan catalog rows that
525    * belong to the specified table. It doesn't specify any columns.
526    * This is a better alternative to just using a start row and scan until
527    * it hits a new table since that requires parsing the HRI to get the table
528    * name.
529    * @param tableName bytes of table's name
530    * @return configured Scan object
531    */
532   @Deprecated
533   public static Scan getScanForTableName(Connection connection, TableName tableName) {
534     // Start key is just the table name with delimiters
535     byte[] startKey = getTableStartRowForMeta(tableName, QueryType.REGION);
536     // Stop key appends the smallest possible char to the table name
537     byte[] stopKey = getTableStopRowForMeta(tableName, QueryType.REGION);
538 
539     Scan scan = getMetaScan(connection);
540     scan.setStartRow(startKey);
541     scan.setStopRow(stopKey);
542     return scan;
543   }
544 
545   private static Scan getMetaScan(Connection connection) {
546     return getMetaScan(connection, Integer.MAX_VALUE);
547   }
548 
549   private static Scan getMetaScan(Connection connection, int rowUpperLimit) {
550     Scan scan = new Scan();
551     int scannerCaching = connection.getConfiguration()
552         .getInt(HConstants.HBASE_META_SCANNER_CACHING,
553             HConstants.DEFAULT_HBASE_META_SCANNER_CACHING);
554     if (connection.getConfiguration().getBoolean(HConstants.USE_META_REPLICAS,
555         HConstants.DEFAULT_USE_META_REPLICAS)) {
556       scan.setConsistency(Consistency.TIMELINE);
557     }
558     if (rowUpperLimit <= scannerCaching) {
559       scan.setSmall(true);
560     }
561     int rows = Math.min(rowUpperLimit, scannerCaching);
562     scan.setCaching(rows);
563     return scan;
564   }
565   /**
566    * Do not use this method to get meta table regions, use methods in MetaTableLocator instead.
567    * @param connection connection we're using
568    * @param tableName table we're looking for
569    * @return Return list of regioninfos and server.
570    * @throws IOException
571    */
572   public static List<Pair<HRegionInfo, ServerName>>
573     getTableRegionsAndLocations(Connection connection, TableName tableName)
574       throws IOException {
575     return getTableRegionsAndLocations(connection, tableName, true);
576   }
577 
578   /**
579    * Do not use this method to get meta table regions, use methods in MetaTableLocator instead.
580    * @param connection connection we're using
581    * @param tableName table to work with, can be null for getting all regions
582    * @param excludeOfflinedSplitParents don't return split parents
583    * @return Return list of regioninfos and server addresses.
584    * @throws IOException
585    */
586   public static List<Pair<HRegionInfo, ServerName>> getTableRegionsAndLocations(
587       Connection connection, @Nullable final TableName tableName,
588       final boolean excludeOfflinedSplitParents) throws IOException {
589     if (tableName != null && tableName.equals(TableName.META_TABLE_NAME)) {
590       throw new IOException("This method can't be used to locate meta regions;"
591         + " use MetaTableLocator instead");
592     }
593     // Make a version of CollectingVisitor that collects HRegionInfo and ServerAddress
594     CollectingVisitor<Pair<HRegionInfo, ServerName>> visitor =
595       new CollectingVisitor<Pair<HRegionInfo, ServerName>>() {
596         private RegionLocations current = null;
597 
598         @Override
599         public boolean visit(Result r) throws IOException {
600           current = getRegionLocations(r);
601           if (current == null || current.getRegionLocation().getRegionInfo() == null) {
602             LOG.warn("No serialized HRegionInfo in " + r);
603             return true;
604           }
605           HRegionInfo hri = current.getRegionLocation().getRegionInfo();
606           if (excludeOfflinedSplitParents && hri.isSplitParent()) return true;
607           // Else call super and add this Result to the collection.
608           return super.visit(r);
609         }
610 
611         @Override
612         void add(Result r) {
613           if (current == null) {
614             return;
615           }
616           for (HRegionLocation loc : current.getRegionLocations()) {
617             if (loc != null) {
618               this.results.add(new Pair<HRegionInfo, ServerName>(
619                 loc.getRegionInfo(), loc.getServerName()));
620             }
621           }
622         }
623       };
624     scanMeta(connection,
625         getTableStartRowForMeta(tableName, QueryType.REGION),
626         getTableStopRowForMeta(tableName, QueryType.REGION),
627         QueryType.REGION, visitor);
628     return visitor.getResults();
629   }
630 
631   /**
632    * @param connection connection we're using
633    * @param serverName server whose regions we're interested in
634    * @return List of user regions installed on this server (does not include
635    * catalog regions).
636    * @throws IOException
637    */
638   public static NavigableMap<HRegionInfo, Result>
639   getServerUserRegions(Connection connection, final ServerName serverName)
640     throws IOException {
641     final NavigableMap<HRegionInfo, Result> hris = new TreeMap<HRegionInfo, Result>();
642     // Fill the above hris map with entries from hbase:meta that have the passed
643     // servername.
644     CollectingVisitor<Result> v = new CollectingVisitor<Result>() {
645       @Override
646       void add(Result r) {
647         if (r == null || r.isEmpty()) return;
648         RegionLocations locations = getRegionLocations(r);
649         if (locations == null) return;
650         for (HRegionLocation loc : locations.getRegionLocations()) {
651           if (loc != null) {
652             if (loc.getServerName() != null && loc.getServerName().equals(serverName)) {
653               hris.put(loc.getRegionInfo(), r);
654             }
655           }
656         }
657       }
658     };
659     scanMeta(connection, null, null, QueryType.REGION, v);
660     return hris;
661   }
662 
663   public static void fullScanMetaAndPrint(Connection connection)
664     throws IOException {
665     Visitor v = new Visitor() {
666       @Override
667       public boolean visit(Result r) throws IOException {
668         if (r ==  null || r.isEmpty()) return true;
669         LOG.info("fullScanMetaAndPrint.Current Meta Row: " + r);
670         TableState state = getTableState(r);
671         if (state != null) {
672           LOG.info("Table State: " + state);
673         } else {
674           RegionLocations locations = getRegionLocations(r);
675           if (locations == null) return true;
676           for (HRegionLocation loc : locations.getRegionLocations()) {
677             if (loc != null) {
678               LOG.info("fullScanMetaAndPrint.HRI Print= " + loc.getRegionInfo());
679             }
680           }
681         }
682         return true;
683       }
684     };
685     scanMeta(connection, null, null, QueryType.ALL, v);
686   }
687 
688   public static void scanMetaForTableRegions(Connection connection,
689       Visitor visitor, TableName tableName) throws IOException {
690     scanMeta(connection, tableName, QueryType.REGION, Integer.MAX_VALUE, visitor);
691   }
692 
693   public static void scanMeta(Connection connection, TableName table,
694       QueryType type, int maxRows, final Visitor visitor) throws IOException {
695     scanMeta(connection, getTableStartRowForMeta(table, type), getTableStopRowForMeta(table, type),
696         type, maxRows, visitor);
697   }
698 
699   public static void scanMeta(Connection connection,
700       @Nullable final byte[] startRow, @Nullable final byte[] stopRow,
701       QueryType type, final Visitor visitor) throws IOException {
702     scanMeta(connection, startRow, stopRow, type, Integer.MAX_VALUE, visitor);
703   }
704 
705   /**
706    * Performs a scan of META table for given table starting from
707    * given row.
708    *
709    * @param connection connection we're using
710    * @param visitor    visitor to call
711    * @param tableName  table withing we scan
712    * @param row        start scan from this row
713    * @param rowLimit   max number of rows to return
714    * @throws IOException
715    */
716   public static void scanMeta(Connection connection,
717       final Visitor visitor, final TableName tableName,
718       final byte[] row, final int rowLimit)
719       throws IOException {
720 
721     byte[] startRow = null;
722     byte[] stopRow = null;
723     if (tableName != null) {
724       startRow =
725           getTableStartRowForMeta(tableName, QueryType.REGION);
726       if (row != null) {
727         HRegionInfo closestRi =
728             getClosestRegionInfo(connection, tableName, row);
729         startRow = HRegionInfo
730             .createRegionName(tableName, closestRi.getStartKey(), HConstants.ZEROES, false);
731       }
732       stopRow =
733           getTableStopRowForMeta(tableName, QueryType.REGION);
734     }
735     scanMeta(connection, startRow, stopRow, QueryType.REGION, rowLimit, visitor);
736   }
737 
738 
739   /**
740    * Performs a scan of META table.
741    * @param connection connection we're using
742    * @param startRow Where to start the scan. Pass null if want to begin scan
743    *                 at first row.
744    * @param stopRow Where to stop the scan. Pass null if want to scan all rows
745    *                from the start one
746    * @param type scanned part of meta
747    * @param maxRows maximum rows to return
748    * @param visitor Visitor invoked against each row.
749    * @throws IOException
750    */
751   public static void scanMeta(Connection connection,
752       @Nullable final byte[] startRow, @Nullable final byte[] stopRow,
753       QueryType type, int maxRows, final Visitor visitor)
754   throws IOException {
755     int rowUpperLimit = maxRows > 0 ? maxRows : Integer.MAX_VALUE;
756     Scan scan = getMetaScan(connection, rowUpperLimit);
757 
758     for (byte[] family : type.getFamilies()) {
759       scan.addFamily(family);
760     }
761     if (startRow != null) scan.setStartRow(startRow);
762     if (stopRow != null) scan.setStopRow(stopRow);
763 
764     if (LOG.isTraceEnabled()) {
765       LOG.trace("Scanning META"
766           + " starting at row=" + Bytes.toStringBinary(startRow)
767           + " stopping at row=" + Bytes.toStringBinary(stopRow)
768           + " for max=" + rowUpperLimit
769           + " with caching=" + scan.getCaching());
770     }
771 
772     int currentRow = 0;
773     try (Table metaTable = getMetaHTable(connection)) {
774       try (ResultScanner scanner = metaTable.getScanner(scan)) {
775         Result data;
776         while ((data = scanner.next()) != null) {
777           if (data.isEmpty()) continue;
778           // Break if visit returns false.
779           if (!visitor.visit(data)) break;
780           if (++currentRow >= rowUpperLimit) break;
781         }
782       }
783     }
784     if (visitor != null && visitor instanceof Closeable) {
785       try {
786         ((Closeable) visitor).close();
787       } catch (Throwable t) {
788         ExceptionUtil.rethrowIfInterrupt(t);
789         LOG.debug("Got exception in closing the meta scanner visitor", t);
790       }
791     }
792   }
793 
794   /**
795    * @return Get closest metatable region row to passed <code>row</code>
796    * @throws java.io.IOException
797    */
798   @Nonnull
799   public static HRegionInfo getClosestRegionInfo(Connection connection,
800       @Nonnull final TableName tableName,
801       @Nonnull final byte[] row)
802       throws IOException {
803     byte[] searchRow = HRegionInfo.createRegionName(tableName, row, HConstants.NINES, false);
804     Scan scan = getMetaScan(connection, 1);
805     scan.setReversed(true);
806     scan.setStartRow(searchRow);
807     try (ResultScanner resultScanner = getMetaHTable(connection).getScanner(scan)) {
808       Result result = resultScanner.next();
809       if (result == null) {
810         throw new TableNotFoundException("Cannot find row in META " +
811             " for table: " + tableName + ", row=" + Bytes.toStringBinary(row));
812       }
813       HRegionInfo regionInfo = getHRegionInfo(result);
814       if (regionInfo == null) {
815         throw new IOException("HRegionInfo was null or empty in Meta for " +
816             tableName + ", row=" + Bytes.toStringBinary(row));
817       }
818       return regionInfo;
819     }
820   }
821 
822   /**
823    * Returns the column family used for meta columns.
824    * @return HConstants.CATALOG_FAMILY.
825    */
826   protected static byte[] getCatalogFamily() {
827     return HConstants.CATALOG_FAMILY;
828   }
829 
830   /**
831    * Returns the column family used for table columns.
832    * @return HConstants.TABLE_FAMILY.
833    */
834   protected static byte[] getTableFamily() {
835     return HConstants.TABLE_FAMILY;
836   }
837 
838   /**
839    * Returns the column qualifier for serialized region info
840    * @return HConstants.REGIONINFO_QUALIFIER
841    */
842   protected static byte[] getRegionInfoColumn() {
843     return HConstants.REGIONINFO_QUALIFIER;
844   }
845 
846   /**
847    * Returns the column qualifier for serialized table state
848    *
849    * @return HConstants.TABLE_STATE_QUALIFIER
850    */
851   protected static byte[] getStateColumn() {
852     return HConstants.TABLE_STATE_QUALIFIER;
853   }
854 
855   /**
856    * Returns the column qualifier for server column for replicaId
857    * @param replicaId the replicaId of the region
858    * @return a byte[] for server column qualifier
859    */
860   @VisibleForTesting
861   public static byte[] getServerColumn(int replicaId) {
862     return replicaId == 0
863       ? HConstants.SERVER_QUALIFIER
864       : Bytes.toBytes(HConstants.SERVER_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
865       + String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId));
866   }
867 
868   /**
869    * Returns the column qualifier for server start code column for replicaId
870    * @param replicaId the replicaId of the region
871    * @return a byte[] for server start code column qualifier
872    */
873   @VisibleForTesting
874   public static byte[] getStartCodeColumn(int replicaId) {
875     return replicaId == 0
876       ? HConstants.STARTCODE_QUALIFIER
877       : Bytes.toBytes(HConstants.STARTCODE_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
878       + String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId));
879   }
880 
881   /**
882    * Returns the column qualifier for seqNum column for replicaId
883    * @param replicaId the replicaId of the region
884    * @return a byte[] for seqNum column qualifier
885    */
886   @VisibleForTesting
887   public static byte[] getSeqNumColumn(int replicaId) {
888     return replicaId == 0
889       ? HConstants.SEQNUM_QUALIFIER
890       : Bytes.toBytes(HConstants.SEQNUM_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
891       + String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId));
892   }
893 
894   /**
895    * Parses the replicaId from the server column qualifier. See top of the class javadoc
896    * for the actual meta layout
897    * @param serverColumn the column qualifier
898    * @return an int for the replicaId
899    */
900   @VisibleForTesting
901   static int parseReplicaIdFromServerColumn(byte[] serverColumn) {
902     String serverStr = Bytes.toString(serverColumn);
903 
904     Matcher matcher = SERVER_COLUMN_PATTERN.matcher(serverStr);
905     if (matcher.matches() && matcher.groupCount() > 0) {
906       String group = matcher.group(1);
907       if (group != null && group.length() > 0) {
908         return Integer.parseInt(group.substring(1), 16);
909       } else {
910         return 0;
911       }
912     }
913     return -1;
914   }
915 
916   /**
917    * Returns a {@link ServerName} from catalog table {@link Result}.
918    * @param r Result to pull from
919    * @return A ServerName instance or null if necessary fields not found or empty.
920    */
921   @Nullable
922   private static ServerName getServerName(final Result r, final int replicaId) {
923     byte[] serverColumn = getServerColumn(replicaId);
924     Cell cell = r.getColumnLatestCell(getCatalogFamily(), serverColumn);
925     if (cell == null || cell.getValueLength() == 0) return null;
926     String hostAndPort = Bytes.toString(
927       cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
928     byte[] startcodeColumn = getStartCodeColumn(replicaId);
929     cell = r.getColumnLatestCell(getCatalogFamily(), startcodeColumn);
930     if (cell == null || cell.getValueLength() == 0) return null;
931     return ServerName.valueOf(hostAndPort,
932       Bytes.toLong(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
933   }
934 
935   /**
936    * The latest seqnum that the server writing to meta observed when opening the region.
937    * E.g. the seqNum when the result of {@link #getServerName(Result, int)} was written.
938    * @param r Result to pull the seqNum from
939    * @return SeqNum, or HConstants.NO_SEQNUM if there's no value written.
940    */
941   private static long getSeqNumDuringOpen(final Result r, final int replicaId) {
942     Cell cell = r.getColumnLatestCell(getCatalogFamily(), getSeqNumColumn(replicaId));
943     if (cell == null || cell.getValueLength() == 0) return HConstants.NO_SEQNUM;
944     return Bytes.toLong(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
945   }
946 
947   /**
948    * Returns an HRegionLocationList extracted from the result.
949    * @return an HRegionLocationList containing all locations for the region range or null if
950    *  we can't deserialize the result.
951    */
952   @Nullable
953   public static RegionLocations getRegionLocations(final Result r) {
954     if (r == null) return null;
955     HRegionInfo regionInfo = getHRegionInfo(r, getRegionInfoColumn());
956     if (regionInfo == null) return null;
957 
958     List<HRegionLocation> locations = new ArrayList<HRegionLocation>(1);
959     NavigableMap<byte[],NavigableMap<byte[],byte[]>> familyMap = r.getNoVersionMap();
960 
961     locations.add(getRegionLocation(r, regionInfo, 0));
962 
963     NavigableMap<byte[], byte[]> infoMap = familyMap.get(getCatalogFamily());
964     if (infoMap == null) return new RegionLocations(locations);
965 
966     // iterate until all serverName columns are seen
967     int replicaId = 0;
968     byte[] serverColumn = getServerColumn(replicaId);
969     SortedMap<byte[], byte[]> serverMap = infoMap.tailMap(serverColumn, false);
970     if (serverMap.isEmpty()) return new RegionLocations(locations);
971 
972     for (Map.Entry<byte[], byte[]> entry : serverMap.entrySet()) {
973       replicaId = parseReplicaIdFromServerColumn(entry.getKey());
974       if (replicaId < 0) {
975         break;
976       }
977       HRegionLocation location = getRegionLocation(r, regionInfo, replicaId);
978       // In case the region replica is newly created, it's location might be null. We usually do not
979       // have HRL's in RegionLocations object with null ServerName. They are handled as null HRLs.
980       if (location == null || location.getServerName() == null) {
981         locations.add(null);
982       } else {
983         locations.add(location);
984       }
985     }
986 
987     return new RegionLocations(locations);
988   }
989 
990   /**
991    * Returns the HRegionLocation parsed from the given meta row Result
992    * for the given regionInfo and replicaId. The regionInfo can be the default region info
993    * for the replica.
994    * @param r the meta row result
995    * @param regionInfo RegionInfo for default replica
996    * @param replicaId the replicaId for the HRegionLocation
997    * @return HRegionLocation parsed from the given meta row Result for the given replicaId
998    */
999   private static HRegionLocation getRegionLocation(final Result r, final HRegionInfo regionInfo,
1000                                                    final int replicaId) {
1001     ServerName serverName = getServerName(r, replicaId);
1002     long seqNum = getSeqNumDuringOpen(r, replicaId);
1003     HRegionInfo replicaInfo = RegionReplicaUtil.getRegionInfoForReplica(regionInfo, replicaId);
1004     return new HRegionLocation(replicaInfo, serverName, seqNum);
1005   }
1006 
1007   /**
1008    * Returns HRegionInfo object from the column
1009    * HConstants.CATALOG_FAMILY:HConstants.REGIONINFO_QUALIFIER of the catalog
1010    * table Result.
1011    * @param data a Result object from the catalog table scan
1012    * @return HRegionInfo or null
1013    */
1014   public static HRegionInfo getHRegionInfo(Result data) {
1015     return getHRegionInfo(data, HConstants.REGIONINFO_QUALIFIER);
1016   }
1017 
1018   /**
1019    * Returns the HRegionInfo object from the column {@link HConstants#CATALOG_FAMILY} and
1020    * <code>qualifier</code> of the catalog table result.
1021    * @param r a Result object from the catalog table scan
1022    * @param qualifier Column family qualifier
1023    * @return An HRegionInfo instance or null.
1024    */
1025   @Nullable
1026   private static HRegionInfo getHRegionInfo(final Result r, byte [] qualifier) {
1027     Cell cell = r.getColumnLatestCell(getCatalogFamily(), qualifier);
1028     if (cell == null) return null;
1029     return HRegionInfo.parseFromOrNull(cell.getValueArray(),
1030       cell.getValueOffset(), cell.getValueLength());
1031   }
1032 
1033   /**
1034    * Returns the daughter regions by reading the corresponding columns of the catalog table
1035    * Result.
1036    * @param data a Result object from the catalog table scan
1037    * @return a pair of HRegionInfo or PairOfSameType(null, null) if the region is not a split
1038    * parent
1039    */
1040   public static PairOfSameType<HRegionInfo> getDaughterRegions(Result data) {
1041     HRegionInfo splitA = getHRegionInfo(data, HConstants.SPLITA_QUALIFIER);
1042     HRegionInfo splitB = getHRegionInfo(data, HConstants.SPLITB_QUALIFIER);
1043 
1044     return new PairOfSameType<HRegionInfo>(splitA, splitB);
1045   }
1046 
1047   /**
1048    * Returns the merge regions by reading the corresponding columns of the catalog table
1049    * Result.
1050    * @param data a Result object from the catalog table scan
1051    * @return a pair of HRegionInfo or PairOfSameType(null, null) if the region is not a split
1052    * parent
1053    */
1054   public static PairOfSameType<HRegionInfo> getMergeRegions(Result data) {
1055     HRegionInfo mergeA = getHRegionInfo(data, HConstants.MERGEA_QUALIFIER);
1056     HRegionInfo mergeB = getHRegionInfo(data, HConstants.MERGEB_QUALIFIER);
1057 
1058     return new PairOfSameType<HRegionInfo>(mergeA, mergeB);
1059   }
1060 
1061   /**
1062    * Fetch table state for given table from META table
1063    * @param conn connection to use
1064    * @param tableName table to fetch state for
1065    * @return state
1066    * @throws IOException
1067    */
1068   @Nullable
1069   public static TableState getTableState(Connection conn, TableName tableName)
1070       throws IOException {
1071     Table metaHTable = getMetaHTable(conn);
1072     Get get = new Get(tableName.getName()).addColumn(getTableFamily(), getStateColumn());
1073     long time = EnvironmentEdgeManager.currentTime();
1074     get.setTimeRange(0, time);
1075     Result result =
1076         metaHTable.get(get);
1077     return getTableState(result);
1078   }
1079 
1080   /**
1081    * Fetch table states from META table
1082    * @param conn connection to use
1083    * @return map {tableName -&gt; state}
1084    * @throws IOException
1085    */
1086   public static Map<TableName, TableState> getTableStates(Connection conn)
1087       throws IOException {
1088     final Map<TableName, TableState> states = new LinkedHashMap<>();
1089     Visitor collector = new Visitor() {
1090       @Override
1091       public boolean visit(Result r) throws IOException {
1092         TableState state = getTableState(r);
1093         if (state != null)
1094           states.put(state.getTableName(), state);
1095         return true;
1096       }
1097     };
1098     fullScanTables(conn, collector);
1099     return states;
1100   }
1101 
1102   /**
1103    * Updates state in META
1104    * @param conn connection to use
1105    * @param tableName table to look for
1106    * @throws IOException
1107    */
1108   public static void updateTableState(Connection conn, TableName tableName,
1109       TableState.State actual) throws IOException {
1110     updateTableState(conn, new TableState(tableName, actual));
1111   }
1112 
1113   /**
1114    * Decode table state from META Result.
1115    * Should contain cell from HConstants.TABLE_FAMILY
1116    * @param r result
1117    * @return null if not found
1118    * @throws IOException
1119    */
1120   @Nullable
1121   public static TableState getTableState(Result r)
1122       throws IOException {
1123     Cell cell = r.getColumnLatestCell(getTableFamily(), getStateColumn());
1124     if (cell == null) return null;
1125     try {
1126       return TableState.parseFrom(TableName.valueOf(r.getRow()),
1127           Arrays.copyOfRange(cell.getValueArray(),
1128           cell.getValueOffset(), cell.getValueOffset() + cell.getValueLength()));
1129     } catch (DeserializationException e) {
1130       throw new IOException(e);
1131     }
1132 
1133   }
1134 
1135   /**
1136    * Implementations 'visit' a catalog table row.
1137    */
1138   public interface Visitor {
1139     /**
1140      * Visit the catalog table row.
1141      * @param r A row from catalog table
1142      * @return True if we are to proceed scanning the table, else false if
1143      * we are to stop now.
1144      */
1145     boolean visit(final Result r) throws IOException;
1146   }
1147 
1148   /**
1149    * Implementations 'visit' a catalog table row but with close() at the end.
1150    */
1151   public interface CloseableVisitor extends Visitor, Closeable {
1152   }
1153 
1154   /**
1155    * A {@link Visitor} that collects content out of passed {@link Result}.
1156    */
1157   static abstract class CollectingVisitor<T> implements Visitor {
1158     final List<T> results = new ArrayList<T>();
1159     @Override
1160     public boolean visit(Result r) throws IOException {
1161       if (r ==  null || r.isEmpty()) return true;
1162       add(r);
1163       return true;
1164     }
1165 
1166     abstract void add(Result r);
1167 
1168     /**
1169      * @return Collected results; wait till visits complete to collect all
1170      * possible results
1171      */
1172     List<T> getResults() {
1173       return this.results;
1174     }
1175   }
1176 
1177   /**
1178    * Collects all returned.
1179    */
1180   static class CollectAllVisitor extends CollectingVisitor<Result> {
1181     @Override
1182     void add(Result r) {
1183       this.results.add(r);
1184     }
1185   }
1186 
1187   /**
1188    * A Visitor that skips offline regions and split parents
1189    */
1190   public static abstract class DefaultVisitorBase implements Visitor {
1191 
1192     public DefaultVisitorBase() {
1193       super();
1194     }
1195 
1196     public abstract boolean visitInternal(Result rowResult) throws IOException;
1197 
1198     @Override
1199     public boolean visit(Result rowResult) throws IOException {
1200       HRegionInfo info = getHRegionInfo(rowResult);
1201       if (info == null) {
1202         return true;
1203       }
1204 
1205       //skip over offline and split regions
1206       if (!(info.isOffline() || info.isSplit())) {
1207         return visitInternal(rowResult);
1208       }
1209       return true;
1210     }
1211   }
1212 
1213   /**
1214    * A Visitor for a table. Provides a consistent view of the table's
1215    * hbase:meta entries during concurrent splits (see HBASE-5986 for details). This class
1216    * does not guarantee ordered traversal of meta entries, and can block until the
1217    * hbase:meta entries for daughters are available during splits.
1218    */
1219   public static abstract class TableVisitorBase extends DefaultVisitorBase {
1220     private TableName tableName;
1221 
1222     public TableVisitorBase(TableName tableName) {
1223       super();
1224       this.tableName = tableName;
1225     }
1226 
1227     @Override
1228     public final boolean visit(Result rowResult) throws IOException {
1229       HRegionInfo info = getHRegionInfo(rowResult);
1230       if (info == null) {
1231         return true;
1232       }
1233       if (!(info.getTable().equals(tableName))) {
1234         return false;
1235       }
1236       return super.visit(rowResult);
1237     }
1238   }
1239 
1240   /**
1241    * Count regions in <code>hbase:meta</code> for passed table.
1242    * @param c Configuration object
1243    * @param tableName table name to count regions for
1244    * @return Count or regions in table <code>tableName</code>
1245    * @throws IOException
1246    */
1247   @Deprecated
1248   public static int getRegionCount(final Configuration c, final String tableName)
1249       throws IOException {
1250     return getRegionCount(c, TableName.valueOf(tableName));
1251   }
1252 
1253   /**
1254    * Count regions in <code>hbase:meta</code> for passed table.
1255    * @param c Configuration object
1256    * @param tableName table name to count regions for
1257    * @return Count or regions in table <code>tableName</code>
1258    * @throws IOException
1259    */
1260   public static int getRegionCount(final Configuration c, final TableName tableName)
1261   throws IOException {
1262     try (Connection connection = ConnectionFactory.createConnection(c)) {
1263       return getRegionCount(connection, tableName);
1264     }
1265   }
1266 
1267   /**
1268    * Count regions in <code>hbase:meta</code> for passed table.
1269    * @param connection Connection object
1270    * @param tableName table name to count regions for
1271    * @return Count or regions in table <code>tableName</code>
1272    * @throws IOException
1273    */
1274   public static int getRegionCount(final Connection connection, final TableName tableName)
1275   throws IOException {
1276     try (RegionLocator locator = connection.getRegionLocator(tableName)) {
1277       List<HRegionLocation> locations = locator.getAllRegionLocations();
1278       return locations == null? 0: locations.size();
1279     }
1280   }
1281 
1282   ////////////////////////
1283   // Editing operations //
1284   ////////////////////////
1285 
1286   /**
1287    * Generates and returns a Put containing the region into for the catalog table
1288    */
1289   public static Put makePutFromRegionInfo(HRegionInfo regionInfo)
1290     throws IOException {
1291     return makePutFromRegionInfo(regionInfo, EnvironmentEdgeManager.currentTime());
1292   }
1293 
1294   /**
1295    * Generates and returns a Put containing the region into for the catalog table
1296    */
1297   public static Put makePutFromRegionInfo(HRegionInfo regionInfo, long ts)
1298     throws IOException {
1299     Put put = new Put(regionInfo.getRegionName(), ts);
1300     addRegionInfo(put, regionInfo);
1301     return put;
1302   }
1303 
1304   /**
1305    * Generates and returns a Delete containing the region info for the catalog
1306    * table
1307    */
1308   public static Delete makeDeleteFromRegionInfo(HRegionInfo regionInfo) {
1309     long now = EnvironmentEdgeManager.currentTime();
1310     return makeDeleteFromRegionInfo(regionInfo, now);
1311   }
1312 
1313   /**
1314    * Generates and returns a Delete containing the region info for the catalog
1315    * table
1316    */
1317   public static Delete makeDeleteFromRegionInfo(HRegionInfo regionInfo, long ts) {
1318     if (regionInfo == null) {
1319       throw new IllegalArgumentException("Can't make a delete for null region");
1320     }
1321     Delete delete = new Delete(regionInfo.getRegionName());
1322     delete.addFamily(getCatalogFamily(), ts);
1323     return delete;
1324   }
1325 
1326   /**
1327    * Adds split daughters to the Put
1328    */
1329   public static Put addDaughtersToPut(Put put, HRegionInfo splitA, HRegionInfo splitB) {
1330     if (splitA != null) {
1331       put.addImmutable(
1332         HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER, splitA.toByteArray());
1333     }
1334     if (splitB != null) {
1335       put.addImmutable(
1336         HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER, splitB.toByteArray());
1337     }
1338     return put;
1339   }
1340 
1341   /**
1342    * Put the passed <code>p</code> to the <code>hbase:meta</code> table.
1343    * @param connection connection we're using
1344    * @param p Put to add to hbase:meta
1345    * @throws IOException
1346    */
1347   static void putToMetaTable(final Connection connection, final Put p)
1348     throws IOException {
1349     put(getMetaHTable(connection), p);
1350   }
1351 
1352   /**
1353    * @param t Table to use (will be closed when done).
1354    * @param p put to make
1355    * @throws IOException
1356    */
1357   private static void put(final Table t, final Put p) throws IOException {
1358     try {
1359       if (METALOG.isDebugEnabled()) {
1360         METALOG.debug(mutationToString(p));
1361       }
1362       t.put(p);
1363     } finally {
1364       t.close();
1365     }
1366   }
1367 
1368   /**
1369    * Put the passed <code>ps</code> to the <code>hbase:meta</code> table.
1370    * @param connection connection we're using
1371    * @param ps Put to add to hbase:meta
1372    * @throws IOException
1373    */
1374   public static void putsToMetaTable(final Connection connection, final List<Put> ps)
1375     throws IOException {
1376     Table t = getMetaHTable(connection);
1377     try {
1378       if (METALOG.isDebugEnabled()) {
1379         METALOG.debug(mutationsToString(ps));
1380       }
1381       t.put(ps);
1382     } finally {
1383       t.close();
1384     }
1385   }
1386 
1387   /**
1388    * Delete the passed <code>d</code> from the <code>hbase:meta</code> table.
1389    * @param connection connection we're using
1390    * @param d Delete to add to hbase:meta
1391    * @throws IOException
1392    */
1393   static void deleteFromMetaTable(final Connection connection, final Delete d)
1394     throws IOException {
1395     List<Delete> dels = new ArrayList<Delete>(1);
1396     dels.add(d);
1397     deleteFromMetaTable(connection, dels);
1398   }
1399 
1400   /**
1401    * Delete the passed <code>deletes</code> from the <code>hbase:meta</code> table.
1402    * @param connection connection we're using
1403    * @param deletes Deletes to add to hbase:meta  This list should support #remove.
1404    * @throws IOException
1405    */
1406   public static void deleteFromMetaTable(final Connection connection, final List<Delete> deletes)
1407     throws IOException {
1408     Table t = getMetaHTable(connection);
1409     try {
1410       if (METALOG.isDebugEnabled()) {
1411         METALOG.debug(mutationsToString(deletes));
1412       }
1413       t.delete(deletes);
1414     } finally {
1415       t.close();
1416     }
1417   }
1418 
1419   /**
1420    * Deletes some replica columns corresponding to replicas for the passed rows
1421    * @param metaRows rows in hbase:meta
1422    * @param replicaIndexToDeleteFrom the replica ID we would start deleting from
1423    * @param numReplicasToRemove how many replicas to remove
1424    * @param connection connection we're using to access meta table
1425    * @throws IOException
1426    */
1427   public static void removeRegionReplicasFromMeta(Set<byte[]> metaRows,
1428     int replicaIndexToDeleteFrom, int numReplicasToRemove, Connection connection)
1429       throws IOException {
1430     int absoluteIndex = replicaIndexToDeleteFrom + numReplicasToRemove;
1431     for (byte[] row : metaRows) {
1432       long now = EnvironmentEdgeManager.currentTime();
1433       Delete deleteReplicaLocations = new Delete(row);
1434       for (int i = replicaIndexToDeleteFrom; i < absoluteIndex; i++) {
1435         deleteReplicaLocations.addColumns(getCatalogFamily(),
1436           getServerColumn(i), now);
1437         deleteReplicaLocations.addColumns(getCatalogFamily(),
1438           getSeqNumColumn(i), now);
1439         deleteReplicaLocations.addColumns(getCatalogFamily(),
1440           getStartCodeColumn(i), now);
1441       }
1442       deleteFromMetaTable(connection, deleteReplicaLocations);
1443     }
1444   }
1445 
1446   /**
1447    * Execute the passed <code>mutations</code> against <code>hbase:meta</code> table.
1448    * @param connection connection we're using
1449    * @param mutations Puts and Deletes to execute on hbase:meta
1450    * @throws IOException
1451    */
1452   public static void mutateMetaTable(final Connection connection,
1453                                      final List<Mutation> mutations)
1454     throws IOException {
1455     Table t = getMetaHTable(connection);
1456     try {
1457       if (METALOG.isDebugEnabled()) {
1458         METALOG.debug(mutationsToString(mutations));
1459       }
1460       t.batch(mutations, null);
1461     } catch (InterruptedException e) {
1462       InterruptedIOException ie = new InterruptedIOException(e.getMessage());
1463       ie.initCause(e);
1464       throw ie;
1465     } finally {
1466       t.close();
1467     }
1468   }
1469 
1470   /**
1471    * Adds a hbase:meta row for the specified new region.
1472    * @param connection connection we're using
1473    * @param regionInfo region information
1474    * @throws IOException if problem connecting or updating meta
1475    */
1476   public static void addRegionToMeta(Connection connection,
1477                                      HRegionInfo regionInfo)
1478     throws IOException {
1479     putToMetaTable(connection, makePutFromRegionInfo(regionInfo));
1480     LOG.info("Added " + regionInfo.getRegionNameAsString());
1481   }
1482 
1483   /**
1484    * Adds a hbase:meta row for the specified new region to the given catalog table. The
1485    * Table is not flushed or closed.
1486    * @param meta the Table for META
1487    * @param regionInfo region information
1488    * @throws IOException if problem connecting or updating meta
1489    */
1490   public static void addRegionToMeta(Table meta, HRegionInfo regionInfo) throws IOException {
1491     addRegionToMeta(meta, regionInfo, null, null);
1492   }
1493 
1494   /**
1495    * Adds a (single) hbase:meta row for the specified new region and its daughters. Note that this
1496    * does not add its daughter's as different rows, but adds information about the daughters
1497    * in the same row as the parent. Use
1498    * {@link #splitRegion(Connection, HRegionInfo, HRegionInfo, HRegionInfo, ServerName, int)}
1499    * if you want to do that.
1500    * @param meta the Table for META
1501    * @param regionInfo region information
1502    * @param splitA first split daughter of the parent regionInfo
1503    * @param splitB second split daughter of the parent regionInfo
1504    * @throws IOException if problem connecting or updating meta
1505    */
1506   public static void addRegionToMeta(Table meta, HRegionInfo regionInfo,
1507                                      HRegionInfo splitA, HRegionInfo splitB) throws IOException {
1508     Put put = makePutFromRegionInfo(regionInfo);
1509     addDaughtersToPut(put, splitA, splitB);
1510     meta.put(put);
1511     if (METALOG.isDebugEnabled()) {
1512       METALOG.debug(mutationToString(put));
1513     }
1514     if (LOG.isDebugEnabled()) {
1515       LOG.debug("Added " + regionInfo.getRegionNameAsString());
1516     }
1517   }
1518 
1519   /**
1520    * Adds a (single) hbase:meta row for the specified new region and its daughters. Note that this
1521    * does not add its daughter's as different rows, but adds information about the daughters
1522    * in the same row as the parent. Use
1523    * {@link #splitRegion(Connection, HRegionInfo, HRegionInfo, HRegionInfo, ServerName, int)}
1524    * if you want to do that.
1525    * @param connection connection we're using
1526    * @param regionInfo region information
1527    * @param splitA first split daughter of the parent regionInfo
1528    * @param splitB second split daughter of the parent regionInfo
1529    * @throws IOException if problem connecting or updating meta
1530    */
1531   public static void addRegionToMeta(Connection connection, HRegionInfo regionInfo,
1532                                      HRegionInfo splitA, HRegionInfo splitB) throws IOException {
1533     Table meta = getMetaHTable(connection);
1534     try {
1535       addRegionToMeta(meta, regionInfo, splitA, splitB);
1536     } finally {
1537       meta.close();
1538     }
1539   }
1540 
1541   /**
1542    * Adds a hbase:meta row for each of the specified new regions.
1543    * @param connection connection we're using
1544    * @param regionInfos region information list
1545    * @throws IOException if problem connecting or updating meta
1546    */
1547   public static void addRegionsToMeta(Connection connection,
1548                                       List<HRegionInfo> regionInfos, int regionReplication)
1549     throws IOException {
1550     addRegionsToMeta(connection, regionInfos, regionReplication, HConstants.LATEST_TIMESTAMP);
1551   }
1552   /**
1553    * Adds a hbase:meta row for each of the specified new regions.
1554    * @param connection connection we're using
1555    * @param regionInfos region information list
1556    * @param regionReplication
1557    * @param ts desired timestamp
1558    * @throws IOException if problem connecting or updating meta
1559    */
1560   public static void addRegionsToMeta(Connection connection,
1561       List<HRegionInfo> regionInfos, int regionReplication, long ts)
1562           throws IOException {
1563     List<Put> puts = new ArrayList<Put>();
1564     for (HRegionInfo regionInfo : regionInfos) {
1565       if (RegionReplicaUtil.isDefaultReplica(regionInfo)) {
1566         Put put = makePutFromRegionInfo(regionInfo, ts);
1567         // Add empty locations for region replicas so that number of replicas can be cached
1568         // whenever the primary region is looked up from meta
1569         for (int i = 1; i < regionReplication; i++) {
1570           addEmptyLocation(put, i);
1571         }
1572         puts.add(put);
1573       }
1574     }
1575     putsToMetaTable(connection, puts);
1576     LOG.info("Added " + puts.size());
1577   }
1578 
1579   /**
1580    * Adds a daughter region entry to meta.
1581    * @param regionInfo the region to put
1582    * @param sn the location of the region
1583    * @param openSeqNum the latest sequence number obtained when the region was open
1584    */
1585   public static void addDaughter(final Connection connection,
1586       final HRegionInfo regionInfo, final ServerName sn, final long openSeqNum)
1587       throws NotAllMetaRegionsOnlineException, IOException {
1588     long now = EnvironmentEdgeManager.currentTime();
1589     Put put = new Put(regionInfo.getRegionName(), now);
1590     addRegionInfo(put, regionInfo);
1591     if (sn != null) {
1592       addLocation(put, sn, openSeqNum, -1, regionInfo.getReplicaId());
1593     }
1594     putToMetaTable(connection, put);
1595     LOG.info("Added daughter " + regionInfo.getEncodedName() +
1596       (sn == null? ", serverName=null": ", serverName=" + sn.toString()));
1597   }
1598 
1599   /**
1600    * Merge the two regions into one in an atomic operation. Deletes the two
1601    * merging regions in hbase:meta and adds the merged region with the information of
1602    * two merging regions.
1603    * @param connection connection we're using
1604    * @param mergedRegion the merged region
1605    * @param regionA
1606    * @param regionB
1607    * @param sn the location of the region
1608    * @param masterSystemTime
1609    * @throws IOException
1610    */
1611   public static void mergeRegions(final Connection connection, HRegionInfo mergedRegion,
1612       HRegionInfo regionA, HRegionInfo regionB, ServerName sn, int regionReplication,
1613       long masterSystemTime)
1614           throws IOException {
1615     Table meta = getMetaHTable(connection);
1616     try {
1617       HRegionInfo copyOfMerged = new HRegionInfo(mergedRegion);
1618 
1619       // use the maximum of what master passed us vs local time.
1620       long time = Math.max(EnvironmentEdgeManager.currentTime(), masterSystemTime);
1621 
1622       // Put for parent
1623       Put putOfMerged = makePutFromRegionInfo(copyOfMerged, time);
1624       putOfMerged.addImmutable(HConstants.CATALOG_FAMILY, HConstants.MERGEA_QUALIFIER,
1625         regionA.toByteArray());
1626       putOfMerged.addImmutable(HConstants.CATALOG_FAMILY, HConstants.MERGEB_QUALIFIER,
1627         regionB.toByteArray());
1628 
1629       // Deletes for merging regions
1630       Delete deleteA = makeDeleteFromRegionInfo(regionA, time);
1631       Delete deleteB = makeDeleteFromRegionInfo(regionB, time);
1632 
1633       // The merged is a new region, openSeqNum = 1 is fine.
1634       addLocation(putOfMerged, sn, 1, -1, mergedRegion.getReplicaId());
1635 
1636       // Add empty locations for region replicas of the merged region so that number of replicas can
1637       // be cached whenever the primary region is looked up from meta
1638       for (int i = 1; i < regionReplication; i++) {
1639         addEmptyLocation(putOfMerged, i);
1640       }
1641 
1642       byte[] tableRow = Bytes.toBytes(mergedRegion.getRegionNameAsString()
1643         + HConstants.DELIMITER);
1644       multiMutate(meta, tableRow, putOfMerged, deleteA, deleteB);
1645     } finally {
1646       meta.close();
1647     }
1648   }
1649 
1650   /**
1651    * Splits the region into two in an atomic operation. Offlines the parent
1652    * region with the information that it is split into two, and also adds
1653    * the daughter regions. Does not add the location information to the daughter
1654    * regions since they are not open yet.
1655    * @param connection connection we're using
1656    * @param parent the parent region which is split
1657    * @param splitA Split daughter region A
1658    * @param splitB Split daughter region A
1659    * @param sn the location of the region
1660    */
1661   public static void splitRegion(final Connection connection,
1662                                  HRegionInfo parent, HRegionInfo splitA, HRegionInfo splitB,
1663                                  ServerName sn, int regionReplication) throws IOException {
1664     Table meta = getMetaHTable(connection);
1665     try {
1666       HRegionInfo copyOfParent = new HRegionInfo(parent);
1667       copyOfParent.setOffline(true);
1668       copyOfParent.setSplit(true);
1669 
1670       //Put for parent
1671       Put putParent = makePutFromRegionInfo(copyOfParent);
1672       addDaughtersToPut(putParent, splitA, splitB);
1673 
1674       //Puts for daughters
1675       Put putA = makePutFromRegionInfo(splitA);
1676       Put putB = makePutFromRegionInfo(splitB);
1677 
1678       addLocation(putA, sn, 1, -1, splitA.getReplicaId()); //new regions, openSeqNum = 1 is fine.
1679       addLocation(putB, sn, 1, -1, splitB.getReplicaId());
1680 
1681       // Add empty locations for region replicas of daughters so that number of replicas can be
1682       // cached whenever the primary region is looked up from meta
1683       for (int i = 1; i < regionReplication; i++) {
1684         addEmptyLocation(putA, i);
1685         addEmptyLocation(putB, i);
1686       }
1687 
1688       byte[] tableRow = Bytes.toBytes(parent.getRegionNameAsString() + HConstants.DELIMITER);
1689       multiMutate(meta, tableRow, putParent, putA, putB);
1690     } finally {
1691       meta.close();
1692     }
1693   }
1694 
1695   /**
1696    * Update state of the table in meta.
1697    * @param connection what we use for update
1698    * @param state new state
1699    * @throws IOException
1700    */
1701   public static void updateTableState(Connection connection, TableState state)
1702       throws IOException {
1703     Put put = makePutFromTableState(state);
1704     putToMetaTable(connection, put);
1705     LOG.info(
1706         "Updated table " + state.getTableName() + " state to " + state.getState() + " in META");
1707   }
1708 
1709   /**
1710    * Construct PUT for given state
1711    * @param state new state
1712    */
1713   public static Put makePutFromTableState(TableState state) {
1714     long time = EnvironmentEdgeManager.currentTime();
1715     Put put = new Put(state.getTableName().getName(), time);
1716     put.add(getTableFamily(), getStateColumn(), state.convert().toByteArray());
1717     return put;
1718   }
1719 
1720   /**
1721    * Remove state for table from meta
1722    * @param connection to use for deletion
1723    * @param table to delete state for
1724    */
1725   public static void deleteTableState(Connection connection, TableName table)
1726       throws IOException {
1727     long time = EnvironmentEdgeManager.currentTime();
1728     Delete delete = new Delete(table.getName());
1729     delete.addColumns(getTableFamily(), getStateColumn(), time);
1730     deleteFromMetaTable(connection, delete);
1731     LOG.info("Deleted table " + table + " state from META");
1732   }
1733 
1734   /**
1735    * Performs an atomic multi-Mutate operation against the given table.
1736    */
1737   private static void multiMutate(Table table, byte[] row, Mutation... mutations)
1738       throws IOException {
1739     CoprocessorRpcChannel channel = table.coprocessorService(row);
1740     MultiRowMutationProtos.MutateRowsRequest.Builder mmrBuilder
1741       = MultiRowMutationProtos.MutateRowsRequest.newBuilder();
1742     if (METALOG.isDebugEnabled()) {
1743       METALOG.debug(mutationsToString(mutations));
1744     }
1745     for (Mutation mutation : mutations) {
1746       if (mutation instanceof Put) {
1747         mmrBuilder.addMutationRequest(ProtobufUtil.toMutation(
1748           ClientProtos.MutationProto.MutationType.PUT, mutation));
1749       } else if (mutation instanceof Delete) {
1750         mmrBuilder.addMutationRequest(ProtobufUtil.toMutation(
1751           ClientProtos.MutationProto.MutationType.DELETE, mutation));
1752       } else {
1753         throw new DoNotRetryIOException("multi in MetaEditor doesn't support "
1754           + mutation.getClass().getName());
1755       }
1756     }
1757 
1758     MultiRowMutationProtos.MultiRowMutationService.BlockingInterface service =
1759       MultiRowMutationProtos.MultiRowMutationService.newBlockingStub(channel);
1760     try {
1761       service.mutateRows(null, mmrBuilder.build());
1762     } catch (ServiceException ex) {
1763       ProtobufUtil.toIOException(ex);
1764     }
1765   }
1766 
1767   /**
1768    * Updates the location of the specified region in hbase:meta to be the specified
1769    * server hostname and startcode.
1770    * <p>
1771    * Uses passed catalog tracker to get a connection to the server hosting
1772    * hbase:meta and makes edits to that region.
1773    *
1774    * @param connection connection we're using
1775    * @param regionInfo region to update location of
1776    * @param openSeqNum the latest sequence number obtained when the region was open
1777    * @param sn Server name
1778    * @param masterSystemTime wall clock time from master if passed in the open region RPC or -1
1779    * @throws IOException
1780    */
1781   public static void updateRegionLocation(Connection connection,
1782                                           HRegionInfo regionInfo, ServerName sn, long openSeqNum,
1783                                           long masterSystemTime)
1784     throws IOException {
1785     updateLocation(connection, regionInfo, sn, openSeqNum, masterSystemTime);
1786   }
1787 
1788   /**
1789    * Updates the location of the specified region to be the specified server.
1790    * <p>
1791    * Connects to the specified server which should be hosting the specified
1792    * catalog region name to perform the edit.
1793    *
1794    * @param connection connection we're using
1795    * @param regionInfo region to update location of
1796    * @param sn Server name
1797    * @param openSeqNum the latest sequence number obtained when the region was open
1798    * @param masterSystemTime wall clock time from master if passed in the open region RPC or -1
1799    * @throws IOException In particular could throw {@link java.net.ConnectException}
1800    * if the server is down on other end.
1801    */
1802   private static void updateLocation(final Connection connection,
1803                                      HRegionInfo regionInfo, ServerName sn, long openSeqNum,
1804                                      long masterSystemTime)
1805     throws IOException {
1806 
1807     // use the maximum of what master passed us vs local time.
1808     long time = Math.max(EnvironmentEdgeManager.currentTime(), masterSystemTime);
1809 
1810     // region replicas are kept in the primary region's row
1811     Put put = new Put(getMetaKeyForRegion(regionInfo), time);
1812     addLocation(put, sn, openSeqNum, time, regionInfo.getReplicaId());
1813     putToMetaTable(connection, put);
1814     LOG.info("Updated row " + regionInfo.getRegionNameAsString() +
1815       " with server=" + sn);
1816   }
1817 
1818   /**
1819    * Deletes the specified region from META.
1820    * @param connection connection we're using
1821    * @param regionInfo region to be deleted from META
1822    * @throws IOException
1823    */
1824   public static void deleteRegion(Connection connection,
1825                                   HRegionInfo regionInfo)
1826     throws IOException {
1827     long time = EnvironmentEdgeManager.currentTime();
1828     Delete delete = new Delete(regionInfo.getRegionName());
1829     delete.addFamily(getCatalogFamily(), time);
1830     deleteFromMetaTable(connection, delete);
1831     LOG.info("Deleted " + regionInfo.getRegionNameAsString());
1832   }
1833 
1834   /**
1835    * Deletes the specified regions from META.
1836    * @param connection connection we're using
1837    * @param regionsInfo list of regions to be deleted from META
1838    * @throws IOException
1839    */
1840   public static void deleteRegions(Connection connection,
1841                                    List<HRegionInfo> regionsInfo) throws IOException {
1842     deleteRegions(connection, regionsInfo, EnvironmentEdgeManager.currentTime());
1843   }
1844   /**
1845    * Deletes the specified regions from META.
1846    * @param connection connection we're using
1847    * @param regionsInfo list of regions to be deleted from META
1848    * @throws IOException
1849    */
1850   public static void deleteRegions(Connection connection,
1851                                    List<HRegionInfo> regionsInfo, long ts) throws IOException {
1852     List<Delete> deletes = new ArrayList<Delete>(regionsInfo.size());
1853     for (HRegionInfo hri: regionsInfo) {
1854       Delete e = new Delete(hri.getRegionName());
1855       e.addFamily(getCatalogFamily(), ts);
1856       deletes.add(e);
1857     }
1858     deleteFromMetaTable(connection, deletes);
1859     LOG.info("Deleted " + regionsInfo);
1860   }
1861 
1862   /**
1863    * Adds and Removes the specified regions from hbase:meta
1864    * @param connection connection we're using
1865    * @param regionsToRemove list of regions to be deleted from META
1866    * @param regionsToAdd list of regions to be added to META
1867    * @throws IOException
1868    */
1869   public static void mutateRegions(Connection connection,
1870                                    final List<HRegionInfo> regionsToRemove,
1871                                    final List<HRegionInfo> regionsToAdd)
1872     throws IOException {
1873     List<Mutation> mutation = new ArrayList<Mutation>();
1874     if (regionsToRemove != null) {
1875       for (HRegionInfo hri: regionsToRemove) {
1876         mutation.add(makeDeleteFromRegionInfo(hri));
1877       }
1878     }
1879     if (regionsToAdd != null) {
1880       for (HRegionInfo hri: regionsToAdd) {
1881         mutation.add(makePutFromRegionInfo(hri));
1882       }
1883     }
1884     mutateMetaTable(connection, mutation);
1885     if (regionsToRemove != null && regionsToRemove.size() > 0) {
1886       LOG.debug("Deleted " + regionsToRemove);
1887     }
1888     if (regionsToAdd != null && regionsToAdd.size() > 0) {
1889       LOG.debug("Added " + regionsToAdd);
1890     }
1891   }
1892 
1893   /**
1894    * Overwrites the specified regions from hbase:meta
1895    * @param connection connection we're using
1896    * @param regionInfos list of regions to be added to META
1897    * @throws IOException
1898    */
1899   public static void overwriteRegions(Connection connection,
1900       List<HRegionInfo> regionInfos, int regionReplication) throws IOException {
1901     // use master time for delete marker and the Put
1902     long now = EnvironmentEdgeManager.currentTime();
1903     deleteRegions(connection, regionInfos, now);
1904     // Why sleep? This is the easiest way to ensure that the previous deletes does not
1905     // eclipse the following puts, that might happen in the same ts from the server.
1906     // See HBASE-9906, and HBASE-9879. Once either HBASE-9879, HBASE-8770 is fixed,
1907     // or HBASE-9905 is fixed and meta uses seqIds, we do not need the sleep.
1908     //
1909     // HBASE-13875 uses master timestamp for the mutations. The 20ms sleep is not needed
1910     addRegionsToMeta(connection, regionInfos, regionReplication, now+1);
1911     LOG.info("Overwritten " + regionInfos);
1912   }
1913 
1914   /**
1915    * Deletes merge qualifiers for the specified merged region.
1916    * @param connection connection we're using
1917    * @param mergedRegion
1918    * @throws IOException
1919    */
1920   public static void deleteMergeQualifiers(Connection connection,
1921                                            final HRegionInfo mergedRegion) throws IOException {
1922     long time = EnvironmentEdgeManager.currentTime();
1923     Delete delete = new Delete(mergedRegion.getRegionName());
1924     delete.addColumns(getCatalogFamily(), HConstants.MERGEA_QUALIFIER, time);
1925     delete.addColumns(getCatalogFamily(), HConstants.MERGEB_QUALIFIER, time);
1926     deleteFromMetaTable(connection, delete);
1927     LOG.info("Deleted references in merged region "
1928       + mergedRegion.getRegionNameAsString() + ", qualifier="
1929       + Bytes.toStringBinary(HConstants.MERGEA_QUALIFIER) + " and qualifier="
1930       + Bytes.toStringBinary(HConstants.MERGEB_QUALIFIER));
1931   }
1932 
1933   private static Put addRegionInfo(final Put p, final HRegionInfo hri)
1934     throws IOException {
1935     p.addImmutable(getCatalogFamily(), HConstants.REGIONINFO_QUALIFIER,
1936       hri.toByteArray());
1937     return p;
1938   }
1939 
1940   public static Put addLocation(final Put p, final ServerName sn, long openSeqNum,
1941       long time, int replicaId){
1942     if (time <= 0) {
1943       time = EnvironmentEdgeManager.currentTime();
1944     }
1945     p.addImmutable(getCatalogFamily(), getServerColumn(replicaId), time,
1946       Bytes.toBytes(sn.getHostAndPort()));
1947     p.addImmutable(getCatalogFamily(), getStartCodeColumn(replicaId), time,
1948       Bytes.toBytes(sn.getStartcode()));
1949     p.addImmutable(getCatalogFamily(), getSeqNumColumn(replicaId), time,
1950       Bytes.toBytes(openSeqNum));
1951     return p;
1952   }
1953 
1954   public static Put addEmptyLocation(final Put p, int replicaId) {
1955     long now = EnvironmentEdgeManager.currentTime();
1956     p.addImmutable(getCatalogFamily(), getServerColumn(replicaId), now, null);
1957     p.addImmutable(getCatalogFamily(), getStartCodeColumn(replicaId), now, null);
1958     p.addImmutable(getCatalogFamily(), getSeqNumColumn(replicaId), now, null);
1959     return p;
1960   }
1961 
1962   private static String mutationsToString(Mutation ... mutations) throws IOException {
1963     StringBuilder sb = new StringBuilder();
1964     String prefix = "";
1965     for (Mutation mutation : mutations) {
1966       sb.append(prefix).append(mutationToString(mutation));
1967       prefix = ", ";
1968     }
1969     return sb.toString();
1970   }
1971 
1972   private static String mutationsToString(List<? extends Mutation> mutations) throws IOException {
1973     StringBuilder sb = new StringBuilder();
1974     String prefix = "";
1975     for (Mutation mutation : mutations) {
1976       sb.append(prefix).append(mutationToString(mutation));
1977       prefix = ", ";
1978     }
1979     return sb.toString();
1980   }
1981 
1982   private static String mutationToString(Mutation p) throws IOException {
1983     return p.getClass().getSimpleName() + p.toJSON();
1984   }
1985 }