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.master.procedure; 019 020import com.google.errorprone.annotations.RestrictedApi; 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.fs.FileSystem; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.TableExistsException; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.TableDescriptor; 036import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 037import org.apache.hadoop.hbase.errorhandling.ForeignException; 038import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher; 039import org.apache.hadoop.hbase.fs.ErasureCodingUtils; 040import org.apache.hadoop.hbase.master.MasterCoprocessorHost; 041import org.apache.hadoop.hbase.master.MasterFileSystem; 042import org.apache.hadoop.hbase.master.MetricsSnapshot; 043import org.apache.hadoop.hbase.master.RegionState; 044import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 045import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure.CreateHdfsRegions; 046import org.apache.hadoop.hbase.monitoring.MonitoredTask; 047import org.apache.hadoop.hbase.monitoring.TaskMonitor; 048import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 049import org.apache.hadoop.hbase.procedure2.util.StringUtils; 050import org.apache.hadoop.hbase.regionserver.storefiletracker.StoreFileTrackerFactory; 051import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; 052import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; 053import org.apache.hadoop.hbase.snapshot.RestoreSnapshotHelper; 054import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; 055import org.apache.hadoop.hbase.snapshot.SnapshotManifest; 056import org.apache.hadoop.hbase.snapshot.SnapshotTTLExpiredException; 057import org.apache.hadoop.hbase.util.CommonFSUtils; 058import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 059import org.apache.hadoop.hbase.util.FSTableDescriptors; 060import org.apache.hadoop.hbase.util.Pair; 061import org.apache.yetus.audience.InterfaceAudience; 062import org.slf4j.Logger; 063import org.slf4j.LoggerFactory; 064 065import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 066 067import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 068import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 069import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CloneSnapshotState; 070import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CloneSnapshotStateData; 071import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.RestoreParentToChildRegionsPair; 072import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; 073 074@InterfaceAudience.Private 075public class CloneSnapshotProcedure extends AbstractStateMachineTableProcedure<CloneSnapshotState> { 076 private static final Logger LOG = LoggerFactory.getLogger(CloneSnapshotProcedure.class); 077 078 private TableDescriptor tableDescriptor; 079 private SnapshotDescription snapshot; 080 private boolean restoreAcl; 081 private String customSFT; 082 private List<RegionInfo> newRegions = null; 083 private Map<String, Pair<String, String>> parentsToChildrenPairMap = new HashMap<>(); 084 085 // Monitor 086 private MonitoredTask monitorStatus = null; 087 088 /** 089 * Constructor (for failover) 090 */ 091 public CloneSnapshotProcedure() { 092 } 093 094 public CloneSnapshotProcedure(final MasterProcedureEnv env, final TableDescriptor tableDescriptor, 095 final SnapshotDescription snapshot) { 096 this(env, tableDescriptor, snapshot, false); 097 } 098 099 /** 100 * Constructor 101 * @param env MasterProcedureEnv 102 * @param tableDescriptor the table to operate on 103 * @param snapshot snapshot to clone from 104 */ 105 public CloneSnapshotProcedure(final MasterProcedureEnv env, final TableDescriptor tableDescriptor, 106 final SnapshotDescription snapshot, final boolean restoreAcl) { 107 this(env, tableDescriptor, snapshot, restoreAcl, null); 108 } 109 110 public CloneSnapshotProcedure(final MasterProcedureEnv env, final TableDescriptor tableDescriptor, 111 final SnapshotDescription snapshot, final boolean restoreAcl, final String customSFT) { 112 super(env); 113 this.tableDescriptor = tableDescriptor; 114 this.snapshot = snapshot; 115 this.restoreAcl = restoreAcl; 116 this.customSFT = customSFT; 117 118 getMonitorStatus(); 119 } 120 121 /** 122 * Set up monitor status if it is not created. 123 */ 124 private MonitoredTask getMonitorStatus() { 125 if (monitorStatus == null) { 126 monitorStatus = TaskMonitor.get() 127 .createStatus("Cloning snapshot '" + snapshot.getName() + "' to table " + getTableName()); 128 } 129 return monitorStatus; 130 } 131 132 private void restoreSnapshotAcl(MasterProcedureEnv env) throws IOException { 133 Configuration conf = env.getMasterServices().getConfiguration(); 134 if ( 135 restoreAcl && snapshot.hasUsersAndPermissions() && snapshot.getUsersAndPermissions() != null 136 && SnapshotDescriptionUtils.isSecurityAvailable(conf) 137 ) { 138 RestoreSnapshotHelper.restoreSnapshotAcl(snapshot, tableDescriptor.getTableName(), conf); 139 } 140 } 141 142 @Override 143 protected Flow executeFromState(final MasterProcedureEnv env, final CloneSnapshotState state) 144 throws InterruptedException { 145 LOG.trace("{} execute state={}", this, state); 146 try { 147 switch (state) { 148 case CLONE_SNAPSHOT_PRE_OPERATION: 149 // Verify if we can clone the table 150 prepareClone(env); 151 152 preCloneSnapshot(env); 153 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_WRITE_FS_LAYOUT); 154 break; 155 case CLONE_SNAPSHOT_WRITE_FS_LAYOUT: 156 updateTableDescriptorWithSFT(); 157 newRegions = createFilesystemLayout(env, tableDescriptor, newRegions); 158 env.getMasterServices().getTableDescriptors().update(tableDescriptor, true); 159 if (tableDescriptor.getErasureCodingPolicy() != null) { 160 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_SET_ERASURE_CODING_POLICY); 161 } else { 162 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_ADD_TO_META); 163 } 164 break; 165 case CLONE_SNAPSHOT_SET_ERASURE_CODING_POLICY: 166 ErasureCodingUtils.setPolicy(env.getMasterFileSystem().getFileSystem(), 167 env.getMasterFileSystem().getRootDir(), getTableName(), 168 tableDescriptor.getErasureCodingPolicy()); 169 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_ADD_TO_META); 170 break; 171 case CLONE_SNAPSHOT_ADD_TO_META: 172 addRegionsToMeta(env); 173 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_ASSIGN_REGIONS); 174 break; 175 case CLONE_SNAPSHOT_ASSIGN_REGIONS: 176 CreateTableProcedure.setEnablingState(env, getTableName()); 177 178 // Separate newRegions to split regions and regions to assign 179 List<RegionInfo> splitRegions = new ArrayList<>(); 180 List<RegionInfo> regionsToAssign = new ArrayList<>(); 181 newRegions.forEach(ri -> { 182 if (ri.isOffline() && (ri.isSplit() || ri.isSplitParent())) { 183 splitRegions.add(ri); 184 } else { 185 regionsToAssign.add(ri); 186 } 187 }); 188 189 // For split regions, add them to RegionStates 190 AssignmentManager am = env.getAssignmentManager(); 191 splitRegions 192 .forEach(ri -> am.getRegionStates().updateRegionState(ri, RegionState.State.SPLIT)); 193 194 addChildProcedure( 195 env.getAssignmentManager().createRoundRobinAssignProcedures(regionsToAssign)); 196 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_UPDATE_DESC_CACHE); 197 break; 198 case CLONE_SNAPSHOT_UPDATE_DESC_CACHE: 199 // XXX: this stage should be named as set table enabled, as now we will cache the 200 // descriptor after writing fs layout. 201 CreateTableProcedure.setEnabledState(env, getTableName()); 202 setNextState(CloneSnapshotState.CLONE_SNAPHOST_RESTORE_ACL); 203 break; 204 case CLONE_SNAPHOST_RESTORE_ACL: 205 restoreSnapshotAcl(env); 206 setNextState(CloneSnapshotState.CLONE_SNAPSHOT_POST_OPERATION); 207 break; 208 case CLONE_SNAPSHOT_POST_OPERATION: 209 postCloneSnapshot(env); 210 211 MetricsSnapshot metricsSnapshot = new MetricsSnapshot(); 212 metricsSnapshot.addSnapshotClone( 213 getMonitorStatus().getCompletionTimestamp() - getMonitorStatus().getStartTime()); 214 getMonitorStatus().markComplete("Clone snapshot '" + snapshot.getName() + "' completed!"); 215 return Flow.NO_MORE_STATE; 216 default: 217 throw new UnsupportedOperationException("unhandled state=" + state); 218 } 219 } catch (IOException e) { 220 if (isRollbackSupported(state)) { 221 setFailure("master-clone-snapshot", e); 222 } else { 223 LOG.warn("Retriable error trying to clone snapshot=" + snapshot.getName() + " to table=" 224 + getTableName() + " state=" + state, e); 225 } 226 } 227 return Flow.HAS_MORE_STATE; 228 } 229 230 /** 231 * If a StoreFileTracker is specified we strip the TableDescriptor from previous SFT config and 232 * set the specified SFT on the table level 233 */ 234 private void updateTableDescriptorWithSFT() { 235 if (StringUtils.isEmpty(customSFT)) { 236 return; 237 } 238 239 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableDescriptor); 240 builder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, customSFT); 241 for (ColumnFamilyDescriptor family : tableDescriptor.getColumnFamilies()) { 242 ColumnFamilyDescriptorBuilder cfBuilder = ColumnFamilyDescriptorBuilder.newBuilder(family); 243 cfBuilder.setConfiguration(StoreFileTrackerFactory.TRACKER_IMPL, null); 244 cfBuilder.setValue(StoreFileTrackerFactory.TRACKER_IMPL, null); 245 builder.modifyColumnFamily(cfBuilder.build()); 246 } 247 tableDescriptor = builder.build(); 248 } 249 250 private void validateSFT() { 251 if (StringUtils.isEmpty(customSFT)) { 252 return; 253 } 254 255 // if customSFT is invalid getTrackerClass will throw a RuntimeException 256 Configuration sftConfig = new Configuration(); 257 sftConfig.set(StoreFileTrackerFactory.TRACKER_IMPL, customSFT); 258 StoreFileTrackerFactory.getTrackerClass(sftConfig); 259 } 260 261 @Override 262 protected void rollbackState(final MasterProcedureEnv env, final CloneSnapshotState state) 263 throws IOException { 264 if (state == CloneSnapshotState.CLONE_SNAPSHOT_PRE_OPERATION) { 265 DeleteTableProcedure.deleteTableStates(env, getTableName()); 266 // TODO-MAYBE: call the deleteTable coprocessor event? 267 return; 268 } 269 270 // The procedure doesn't have a rollback. The execution will succeed, at some point. 271 throw new UnsupportedOperationException("unhandled state=" + state); 272 } 273 274 @Override 275 protected boolean isRollbackSupported(final CloneSnapshotState state) { 276 switch (state) { 277 case CLONE_SNAPSHOT_PRE_OPERATION: 278 return true; 279 default: 280 return false; 281 } 282 } 283 284 @Override 285 protected CloneSnapshotState getState(final int stateId) { 286 return CloneSnapshotState.valueOf(stateId); 287 } 288 289 @Override 290 protected int getStateId(final CloneSnapshotState state) { 291 return state.getNumber(); 292 } 293 294 @Override 295 protected CloneSnapshotState getInitialState() { 296 return CloneSnapshotState.CLONE_SNAPSHOT_PRE_OPERATION; 297 } 298 299 @Override 300 public TableName getTableName() { 301 return tableDescriptor.getTableName(); 302 } 303 304 @Override 305 public TableOperationType getTableOperationType() { 306 return TableOperationType.CREATE; // Clone is creating a table 307 } 308 309 @Override 310 public void toStringClassDetails(StringBuilder sb) { 311 sb.append(getClass().getSimpleName()); 312 sb.append(" (table="); 313 sb.append(getTableName()); 314 sb.append(" snapshot="); 315 sb.append(snapshot); 316 sb.append(")"); 317 } 318 319 @Override 320 protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException { 321 super.serializeStateData(serializer); 322 323 CloneSnapshotStateData.Builder cloneSnapshotMsg = CloneSnapshotStateData.newBuilder() 324 .setUserInfo(MasterProcedureUtil.toProtoUserInfo(getUser())).setSnapshot(this.snapshot) 325 .setTableSchema(ProtobufUtil.toTableSchema(tableDescriptor)); 326 327 cloneSnapshotMsg.setRestoreAcl(restoreAcl); 328 if (newRegions != null) { 329 for (RegionInfo hri : newRegions) { 330 cloneSnapshotMsg.addRegionInfo(ProtobufUtil.toRegionInfo(hri)); 331 } 332 } 333 if (!parentsToChildrenPairMap.isEmpty()) { 334 final Iterator<Map.Entry<String, Pair<String, String>>> it = 335 parentsToChildrenPairMap.entrySet().iterator(); 336 while (it.hasNext()) { 337 final Map.Entry<String, Pair<String, String>> entry = it.next(); 338 339 RestoreParentToChildRegionsPair.Builder parentToChildrenPair = 340 RestoreParentToChildRegionsPair.newBuilder().setParentRegionName(entry.getKey()) 341 .setChild1RegionName(entry.getValue().getFirst()) 342 .setChild2RegionName(entry.getValue().getSecond()); 343 cloneSnapshotMsg.addParentToChildRegionsPairList(parentToChildrenPair); 344 } 345 } 346 if (!StringUtils.isEmpty(customSFT)) { 347 cloneSnapshotMsg.setCustomSFT(customSFT); 348 } 349 serializer.serialize(cloneSnapshotMsg.build()); 350 } 351 352 @Override 353 protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException { 354 super.deserializeStateData(serializer); 355 356 CloneSnapshotStateData cloneSnapshotMsg = serializer.deserialize(CloneSnapshotStateData.class); 357 setUser(MasterProcedureUtil.toUserInfo(cloneSnapshotMsg.getUserInfo())); 358 snapshot = cloneSnapshotMsg.getSnapshot(); 359 tableDescriptor = ProtobufUtil.toTableDescriptor(cloneSnapshotMsg.getTableSchema()); 360 if (cloneSnapshotMsg.hasRestoreAcl()) { 361 restoreAcl = cloneSnapshotMsg.getRestoreAcl(); 362 } 363 if (cloneSnapshotMsg.getRegionInfoCount() == 0) { 364 newRegions = null; 365 } else { 366 newRegions = new ArrayList<>(cloneSnapshotMsg.getRegionInfoCount()); 367 for (HBaseProtos.RegionInfo hri : cloneSnapshotMsg.getRegionInfoList()) { 368 newRegions.add(ProtobufUtil.toRegionInfo(hri)); 369 } 370 } 371 if (cloneSnapshotMsg.getParentToChildRegionsPairListCount() > 0) { 372 parentsToChildrenPairMap = new HashMap<>(); 373 for (RestoreParentToChildRegionsPair parentToChildrenPair : cloneSnapshotMsg 374 .getParentToChildRegionsPairListList()) { 375 parentsToChildrenPairMap.put(parentToChildrenPair.getParentRegionName(), new Pair<>( 376 parentToChildrenPair.getChild1RegionName(), parentToChildrenPair.getChild2RegionName())); 377 } 378 } 379 if (!StringUtils.isEmpty(cloneSnapshotMsg.getCustomSFT())) { 380 customSFT = cloneSnapshotMsg.getCustomSFT(); 381 } 382 // Make sure that the monitor status is set up 383 getMonitorStatus(); 384 } 385 386 /** 387 * Action before any real action of cloning from snapshot. 388 * @param env MasterProcedureEnv 389 */ 390 private void prepareClone(final MasterProcedureEnv env) throws IOException { 391 final TableName tableName = getTableName(); 392 if (env.getMasterServices().getTableDescriptors().exists(tableName)) { 393 throw new TableExistsException(tableName); 394 } 395 396 // check whether ttl has expired for this snapshot 397 if ( 398 SnapshotDescriptionUtils.isExpiredSnapshot(snapshot.getTtl(), snapshot.getCreationTime(), 399 EnvironmentEdgeManager.currentTime()) 400 ) { 401 throw new SnapshotTTLExpiredException(ProtobufUtil.createSnapshotDesc(snapshot)); 402 } 403 404 validateSFT(); 405 } 406 407 /** 408 * Action before cloning from snapshot. 409 * @param env MasterProcedureEnv 410 */ 411 private void preCloneSnapshot(final MasterProcedureEnv env) 412 throws IOException, InterruptedException { 413 if (!getTableName().isSystemTable()) { 414 // Check and update namespace quota 415 final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem(); 416 417 SnapshotManifest manifest = 418 SnapshotManifest.open(env.getMasterConfiguration(), mfs.getFileSystem(), 419 SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, mfs.getRootDir()), snapshot); 420 421 ProcedureSyncWait.getMasterQuotaManager(env).checkNamespaceTableAndRegionQuota(getTableName(), 422 manifest.getRegionManifestsMap().size()); 423 } 424 425 final MasterCoprocessorHost cpHost = env.getMasterCoprocessorHost(); 426 if (cpHost != null) { 427 cpHost.preCreateTableAction(tableDescriptor, null, getUser()); 428 } 429 } 430 431 /** 432 * Action after cloning from snapshot. 433 * @param env MasterProcedureEnv 434 */ 435 private void postCloneSnapshot(final MasterProcedureEnv env) 436 throws IOException, InterruptedException { 437 final MasterCoprocessorHost cpHost = env.getMasterCoprocessorHost(); 438 if (cpHost != null) { 439 final RegionInfo[] regions = 440 (newRegions == null) ? null : newRegions.toArray(new RegionInfo[newRegions.size()]); 441 cpHost.postCompletedCreateTableAction(tableDescriptor, regions, getUser()); 442 } 443 } 444 445 /** 446 * Create regions in file system. 447 * @param env MasterProcedureEnv 448 */ 449 private List<RegionInfo> createFilesystemLayout(final MasterProcedureEnv env, 450 final TableDescriptor tableDescriptor, final List<RegionInfo> newRegions) throws IOException { 451 return createFsLayout(env, tableDescriptor, newRegions, new CreateHdfsRegions() { 452 @Override 453 public List<RegionInfo> createHdfsRegions(final MasterProcedureEnv env, 454 final Path tableRootDir, final TableName tableName, final List<RegionInfo> newRegions) 455 throws IOException { 456 457 final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem(); 458 final FileSystem fs = mfs.getFileSystem(); 459 final Path rootDir = mfs.getRootDir(); 460 final Configuration conf = env.getMasterConfiguration(); 461 final ForeignExceptionDispatcher monitorException = new ForeignExceptionDispatcher(); 462 463 getMonitorStatus().setStatus("Clone snapshot - creating regions for table: " + tableName); 464 465 try { 466 // 1. Execute the on-disk Clone 467 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir); 468 SnapshotManifest manifest = SnapshotManifest.open(conf, fs, snapshotDir, snapshot); 469 RestoreSnapshotHelper restoreHelper = new RestoreSnapshotHelper(conf, fs, manifest, 470 tableDescriptor, tableRootDir, monitorException, monitorStatus); 471 RestoreSnapshotHelper.RestoreMetaChanges metaChanges = restoreHelper.restoreHdfsRegions(); 472 473 // Clone operation should not have stuff to restore or remove 474 Preconditions.checkArgument(!metaChanges.hasRegionsToRestore(), 475 "A clone should not have regions to restore"); 476 Preconditions.checkArgument(!metaChanges.hasRegionsToRemove(), 477 "A clone should not have regions to remove"); 478 479 // At this point the clone is complete. Next step is enabling the table. 480 String msg = 481 "Clone snapshot=" + snapshot.getName() + " on table=" + tableName + " completed!"; 482 LOG.info(msg); 483 monitorStatus.setStatus(msg + " Waiting for table to be enabled..."); 484 485 // 2. Let the next step to add the regions to meta 486 return metaChanges.getRegionsToAdd(); 487 } catch (Exception e) { 488 String msg = "clone snapshot=" + ClientSnapshotDescriptionUtils.toString(snapshot) 489 + " failed because " + e.getMessage(); 490 LOG.error(msg, e); 491 IOException rse = 492 new RestoreSnapshotException(msg, e, ProtobufUtil.createSnapshotDesc(snapshot)); 493 494 // these handlers aren't futures so we need to register the error here. 495 monitorException.receive(new ForeignException("Master CloneSnapshotProcedure", rse)); 496 throw rse; 497 } 498 } 499 }); 500 } 501 502 /** 503 * Create region layout in file system. 504 * @param env MasterProcedureEnv 505 */ 506 private List<RegionInfo> createFsLayout(final MasterProcedureEnv env, 507 final TableDescriptor tableDescriptor, List<RegionInfo> newRegions, 508 final CreateHdfsRegions hdfsRegionHandler) throws IOException { 509 final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem(); 510 511 // 1. Create Table Descriptor 512 // using a copy of descriptor, table will be created enabling first 513 final Path tableDir = 514 CommonFSUtils.getTableDir(mfs.getRootDir(), tableDescriptor.getTableName()); 515 if (CommonFSUtils.isExists(mfs.getFileSystem(), tableDir)) { 516 // if the region dirs exist, will cause exception and unlimited retry (see HBASE-24546) 517 LOG.warn("temp table dir already exists on disk: {}, will be deleted.", tableDir); 518 CommonFSUtils.deleteDirectory(mfs.getFileSystem(), tableDir); 519 } 520 ((FSTableDescriptors) (env.getMasterServices().getTableDescriptors())) 521 .createTableDescriptorForTableDirectory(tableDir, 522 TableDescriptorBuilder.newBuilder(tableDescriptor).build(), false); 523 524 // 2. Create Regions 525 newRegions = hdfsRegionHandler.createHdfsRegions(env, mfs.getRootDir(), 526 tableDescriptor.getTableName(), newRegions); 527 528 return newRegions; 529 } 530 531 /** 532 * Add regions to hbase:meta table. 533 * @param env MasterProcedureEnv 534 */ 535 private void addRegionsToMeta(final MasterProcedureEnv env) throws IOException { 536 newRegions = CreateTableProcedure.addTableToMeta(env, tableDescriptor, newRegions); 537 538 // TODO: parentsToChildrenPairMap is always empty, which makes updateMetaParentRegions() 539 // a no-op. This part seems unnecessary. Figure out. - Appy 12/21/17 540 RestoreSnapshotHelper.RestoreMetaChanges metaChanges = 541 new RestoreSnapshotHelper.RestoreMetaChanges(tableDescriptor, parentsToChildrenPairMap); 542 metaChanges.updateMetaParentRegions(env.getMasterServices().getConnection(), newRegions); 543 } 544 545 /** 546 * Exposed for Testing: HBASE-26462 547 */ 548 @RestrictedApi(explanation = "Should only be called in tests", link = "", 549 allowedOnPath = ".*/src/test/.*") 550 public boolean getRestoreAcl() { 551 return restoreAcl; 552 } 553 554}