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