Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 9E08C200D15 for ; Thu, 5 Oct 2017 17:13:33 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 9C4F4160BE0; Thu, 5 Oct 2017 15:13:33 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 568CF160BEC for ; Thu, 5 Oct 2017 17:13:30 +0200 (CEST) Received: (qmail 79107 invoked by uid 500); 5 Oct 2017 15:13:26 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 77979 invoked by uid 99); 5 Oct 2017 15:13:25 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Oct 2017 15:13:25 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 17765F5CB8; Thu, 5 Oct 2017 15:13:24 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: git-site-role@apache.org To: commits@hbase.apache.org Date: Thu, 05 Oct 2017 15:13:47 -0000 Message-Id: <7657d212af314c09b2d3bd60b1f4ace7@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [25/51] [partial] hbase-site git commit: Published site at . archived-at: Thu, 05 Oct 2017 15:13:33 -0000 http://git-wip-us.apache.org/repos/asf/hbase-site/blob/b838bdf0/devapidocs/src-html/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.html ---------------------------------------------------------------------- diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.html b/devapidocs/src-html/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.html index 7433b34..ca8df99 100644 --- a/devapidocs/src-html/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.html +++ b/devapidocs/src-html/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.html @@ -49,1147 +49,1149 @@ 041import org.apache.hadoop.hbase.MetaTableAccessor; 042import org.apache.hadoop.hbase.Stoppable; 043import org.apache.hadoop.hbase.TableName; -044import org.apache.yetus.audience.InterfaceAudience; -045import org.apache.yetus.audience.InterfaceStability; -046import org.apache.hadoop.hbase.client.TableDescriptor; -047import org.apache.hadoop.hbase.client.TableDescriptorBuilder; -048import org.apache.hadoop.hbase.client.TableState; -049import org.apache.hadoop.hbase.errorhandling.ForeignException; -050import org.apache.hadoop.hbase.executor.ExecutorService; -051import org.apache.hadoop.hbase.ipc.RpcServer; -052import org.apache.hadoop.hbase.master.MasterCoprocessorHost; -053import org.apache.hadoop.hbase.master.MasterFileSystem; -054import org.apache.hadoop.hbase.master.MasterServices; -055import org.apache.hadoop.hbase.master.MetricsMaster; -056import org.apache.hadoop.hbase.master.SnapshotSentinel; -057import org.apache.hadoop.hbase.master.cleaner.HFileCleaner; -058import org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner; -059import org.apache.hadoop.hbase.master.procedure.CloneSnapshotProcedure; -060import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; -061import org.apache.hadoop.hbase.master.procedure.RestoreSnapshotProcedure; -062import org.apache.hadoop.hbase.procedure.MasterProcedureManager; -063import org.apache.hadoop.hbase.procedure.Procedure; -064import org.apache.hadoop.hbase.procedure.ProcedureCoordinator; -065import org.apache.hadoop.hbase.procedure.ProcedureCoordinatorRpcs; -066import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator; -067import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; -068import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; -069import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.NameStringPair; -070import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ProcedureDescription; -071import org.apache.hadoop.hbase.security.AccessDeniedException; -072import org.apache.hadoop.hbase.security.User; -073import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; -074import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription.Type; -075import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; -076import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException; -077import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; -078import org.apache.hadoop.hbase.snapshot.SnapshotCreationException; -079import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; -080import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException; -081import org.apache.hadoop.hbase.snapshot.SnapshotExistsException; -082import org.apache.hadoop.hbase.snapshot.SnapshotManifest; -083import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil; -084import org.apache.hadoop.hbase.snapshot.TablePartiallyOpenException; -085import org.apache.hadoop.hbase.snapshot.UnknownSnapshotException; -086import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; -087import org.apache.hadoop.hbase.util.FSUtils; -088import org.apache.hadoop.hbase.util.KeyLocker; -089import org.apache.hadoop.hbase.util.NonceKey; -090import org.apache.zookeeper.KeeperException; -091 -092/** -093 * This class manages the procedure of taking and restoring snapshots. There is only one -094 * SnapshotManager for the master. -095 * <p> -096 * The class provides methods for monitoring in-progress snapshot actions. -097 * <p> -098 * Note: Currently there can only be one snapshot being taken at a time over the cluster. This is a -099 * simplification in the current implementation. -100 */ -101@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) -102@InterfaceStability.Unstable -103public class SnapshotManager extends MasterProcedureManager implements Stoppable { -104 private static final Log LOG = LogFactory.getLog(SnapshotManager.class); -105 -106 /** By default, check to see if the snapshot is complete every WAKE MILLIS (ms) */ -107 private static final int SNAPSHOT_WAKE_MILLIS_DEFAULT = 500; -108 -109 /** -110 * Wait time before removing a finished sentinel from the in-progress map -111 * -112 * NOTE: This is used as a safety auto cleanup. -113 * The snapshot and restore handlers map entries are removed when a user asks if a snapshot or -114 * restore is completed. This operation is part of the HBaseAdmin snapshot/restore API flow. -115 * In case something fails on the client side and the snapshot/restore state is not reclaimed -116 * after a default timeout, the entry is removed from the in-progress map. -117 * At this point, if the user asks for the snapshot/restore status, the result will be -118 * snapshot done if exists or failed if it doesn't exists. -119 */ -120 private static final int SNAPSHOT_SENTINELS_CLEANUP_TIMEOUT = 60 * 1000; -121 -122 /** Enable or disable snapshot support */ -123 public static final String HBASE_SNAPSHOT_ENABLED = "hbase.snapshot.enabled"; -124 -125 /** -126 * Conf key for # of ms elapsed between checks for snapshot errors while waiting for -127 * completion. -128 */ -129 private static final String SNAPSHOT_WAKE_MILLIS_KEY = "hbase.snapshot.master.wakeMillis"; -130 -131 /** Name of the operation to use in the controller */ -132 public static final String ONLINE_SNAPSHOT_CONTROLLER_DESCRIPTION = "online-snapshot"; -133 -134 /** Conf key for # of threads used by the SnapshotManager thread pool */ -135 private static final String SNAPSHOT_POOL_THREADS_KEY = "hbase.snapshot.master.threads"; -136 -137 /** number of current operations running on the master */ -138 private static final int SNAPSHOT_POOL_THREADS_DEFAULT = 1; -139 -140 private boolean stopped; -141 private MasterServices master; // Needed by TableEventHandlers -142 private ProcedureCoordinator coordinator; -143 -144 // Is snapshot feature enabled? -145 private boolean isSnapshotSupported = false; -146 -147 // Snapshot handlers map, with table name as key. -148 // The map is always accessed and modified under the object lock using synchronized. -149 // snapshotTable() will insert an Handler in the table. -150 // isSnapshotDone() will remove the handler requested if the operation is finished. -151 private Map<TableName, SnapshotSentinel> snapshotHandlers = new HashMap<>(); -152 -153 // Restore map, with table name as key, procedure ID as value. -154 // The map is always accessed and modified under the object lock using synchronized. -155 // restoreSnapshot()/cloneSnapshot() will insert a procedure ID in the map. -156 // -157 // TODO: just as the Apache HBase 1.x implementation, this map would not survive master -158 // restart/failover. This is just a stopgap implementation until implementation of taking -159 // snapshot using Procedure-V2. -160 private Map<TableName, Long> restoreTableToProcIdMap = new HashMap<>(); -161 -162 private Path rootDir; -163 private ExecutorService executorService; -164 -165 /** -166 * Locks for snapshot operations -167 * key is snapshot's filename in progress, value is the related lock -168 * - create snapshot -169 * - SnapshotCleaner -170 * */ -171 private KeyLocker<String> locks = new KeyLocker<>(); -172 +044import org.apache.hadoop.hbase.client.TableDescriptor; +045import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +046import org.apache.hadoop.hbase.client.TableState; +047import org.apache.hadoop.hbase.errorhandling.ForeignException; +048import org.apache.hadoop.hbase.executor.ExecutorService; +049import org.apache.hadoop.hbase.ipc.RpcServer; +050import org.apache.hadoop.hbase.master.MasterCoprocessorHost; +051import org.apache.hadoop.hbase.master.MasterFileSystem; +052import org.apache.hadoop.hbase.master.MasterServices; +053import org.apache.hadoop.hbase.master.MetricsMaster; +054import org.apache.hadoop.hbase.master.SnapshotSentinel; +055import org.apache.hadoop.hbase.master.cleaner.HFileCleaner; +056import org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner; +057import org.apache.hadoop.hbase.master.procedure.CloneSnapshotProcedure; +058import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; +059import org.apache.hadoop.hbase.master.procedure.RestoreSnapshotProcedure; +060import org.apache.hadoop.hbase.procedure.MasterProcedureManager; +061import org.apache.hadoop.hbase.procedure.Procedure; +062import org.apache.hadoop.hbase.procedure.ProcedureCoordinator; +063import org.apache.hadoop.hbase.procedure.ProcedureCoordinatorRpcs; +064import org.apache.hadoop.hbase.procedure.ZKProcedureCoordinator; +065import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; +066import org.apache.hadoop.hbase.security.AccessDeniedException; +067import org.apache.hadoop.hbase.security.User; +068import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; +069import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException; +070import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; +071import org.apache.hadoop.hbase.snapshot.SnapshotCreationException; +072import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils; +073import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException; +074import org.apache.hadoop.hbase.snapshot.SnapshotExistsException; +075import org.apache.hadoop.hbase.snapshot.SnapshotManifest; +076import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil; +077import org.apache.hadoop.hbase.snapshot.TablePartiallyOpenException; +078import org.apache.hadoop.hbase.snapshot.UnknownSnapshotException; +079import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; +080import org.apache.hadoop.hbase.util.FSUtils; +081import org.apache.hadoop.hbase.util.KeyLocker; +082import org.apache.hadoop.hbase.util.NonceKey; +083import org.apache.yetus.audience.InterfaceAudience; +084import org.apache.yetus.audience.InterfaceStability; +085import org.apache.zookeeper.KeeperException; +086 +087import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; +088import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.NameStringPair; +089import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ProcedureDescription; +090import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; +091import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription.Type; +092 +093/** +094 * This class manages the procedure of taking and restoring snapshots. There is only one +095 * SnapshotManager for the master. +096 * <p> +097 * The class provides methods for monitoring in-progress snapshot actions. +098 * <p> +099 * Note: Currently there can only be one snapshot being taken at a time over the cluster. This is a +100 * simplification in the current implementation. +101 */ +102@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) +103@InterfaceStability.Unstable +104public class SnapshotManager extends MasterProcedureManager implements Stoppable { +105 private static final Log LOG = LogFactory.getLog(SnapshotManager.class); +106 +107 /** By default, check to see if the snapshot is complete every WAKE MILLIS (ms) */ +108 private static final int SNAPSHOT_WAKE_MILLIS_DEFAULT = 500; +109 +110 /** +111 * Wait time before removing a finished sentinel from the in-progress map +112 * +113 * NOTE: This is used as a safety auto cleanup. +114 * The snapshot and restore handlers map entries are removed when a user asks if a snapshot or +115 * restore is completed. This operation is part of the HBaseAdmin snapshot/restore API flow. +116 * In case something fails on the client side and the snapshot/restore state is not reclaimed +117 * after a default timeout, the entry is removed from the in-progress map. +118 * At this point, if the user asks for the snapshot/restore status, the result will be +119 * snapshot done if exists or failed if it doesn't exists. +120 */ +121 private static final int SNAPSHOT_SENTINELS_CLEANUP_TIMEOUT = 60 * 1000; +122 +123 /** Enable or disable snapshot support */ +124 public static final String HBASE_SNAPSHOT_ENABLED = "hbase.snapshot.enabled"; +125 +126 /** +127 * Conf key for # of ms elapsed between checks for snapshot errors while waiting for +128 * completion. +129 */ +130 private static final String SNAPSHOT_WAKE_MILLIS_KEY = "hbase.snapshot.master.wakeMillis"; +131 +132 /** Name of the operation to use in the controller */ +133 public static final String ONLINE_SNAPSHOT_CONTROLLER_DESCRIPTION = "online-snapshot"; +134 +135 /** Conf key for # of threads used by the SnapshotManager thread pool */ +136 private static final String SNAPSHOT_POOL_THREADS_KEY = "hbase.snapshot.master.threads"; +137 +138 /** number of current operations running on the master */ +139 private static final int SNAPSHOT_POOL_THREADS_DEFAULT = 1; +140 +141 private boolean stopped; +142 private MasterServices master; // Needed by TableEventHandlers +143 private ProcedureCoordinator coordinator; +144 +145 // Is snapshot feature enabled? +146 private boolean isSnapshotSupported = false; +147 +148 // Snapshot handlers map, with table name as key. +149 // The map is always accessed and modified under the object lock using synchronized. +150 // snapshotTable() will insert an Handler in the table. +151 // isSnapshotDone() will remove the handler requested if the operation is finished. +152 private Map<TableName, SnapshotSentinel> snapshotHandlers = new HashMap<>(); +153 +154 // Restore map, with table name as key, procedure ID as value. +155 // The map is always accessed and modified under the object lock using synchronized. +156 // restoreSnapshot()/cloneSnapshot() will insert a procedure ID in the map. +157 // +158 // TODO: just as the Apache HBase 1.x implementation, this map would not survive master +159 // restart/failover. This is just a stopgap implementation until implementation of taking +160 // snapshot using Procedure-V2. +161 private Map<TableName, Long> restoreTableToProcIdMap = new HashMap<>(); +162 +163 private Path rootDir; +164 private ExecutorService executorService; +165 +166 /** +167 * Locks for snapshot operations +168 * key is snapshot's filename in progress, value is the related lock +169 * - create snapshot +170 * - SnapshotCleaner +171 * */ +172 private KeyLocker<String> locks = new KeyLocker<>(); 173 174 -175 public SnapshotManager() {} -176 -177 /** -178 * Fully specify all necessary components of a snapshot manager. Exposed for testing. -179 * @param master services for the master where the manager is running -180 * @param coordinator procedure coordinator instance. exposed for testing. -181 * @param pool HBase ExecutorServcie instance, exposed for testing. -182 */ -183 public SnapshotManager(final MasterServices master, final MetricsMaster metricsMaster, -184 ProcedureCoordinator coordinator, ExecutorService pool) -185 throws IOException, UnsupportedOperationException { -186 this.master = master; -187 -188 this.rootDir = master.getMasterFileSystem().getRootDir(); -189 checkSnapshotSupport(master.getConfiguration(), master.getMasterFileSystem()); -190 -191 this.coordinator = coordinator; -192 this.executorService = pool; -193 resetTempDir(); -194 } -195 -196 /** -197 * Gets the list of all completed snapshots. -198 * @return list of SnapshotDescriptions -199 * @throws IOException File system exception -200 */ -201 public List<SnapshotDescription> getCompletedSnapshots() throws IOException { -202 return getCompletedSnapshots(SnapshotDescriptionUtils.getSnapshotsDir(rootDir), true); -203 } -204 -205 /** -206 * Gets the list of all completed snapshots. -207 * @param snapshotDir snapshot directory -208 * @param withCpCall Whether to call CP hooks -209 * @return list of SnapshotDescriptions -210 * @throws IOException File system exception -211 */ -212 private List<SnapshotDescription> getCompletedSnapshots(Path snapshotDir, boolean withCpCall) -213 throws IOException { -214 List<SnapshotDescription> snapshotDescs = new ArrayList<>(); -215 // first create the snapshot root path and check to see if it exists -216 FileSystem fs = master.getMasterFileSystem().getFileSystem(); -217 if (snapshotDir == null) snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir); -218 -219 // if there are no snapshots, return an empty list -220 if (!fs.exists(snapshotDir)) { -221 return snapshotDescs; -222 } -223 -224 // ignore all the snapshots in progress -225 FileStatus[] snapshots = fs.listStatus(snapshotDir, -226 new SnapshotDescriptionUtils.CompletedSnaphotDirectoriesFilter(fs)); -227 MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); -228 withCpCall = withCpCall && cpHost != null; -229 // loop through all the completed snapshots -230 for (FileStatus snapshot : snapshots) { -231 Path info = new Path(snapshot.getPath(), SnapshotDescriptionUtils.SNAPSHOTINFO_FILE); -232 // if the snapshot is bad -233 if (!fs.exists(info)) { -234 LOG.error("Snapshot information for " + snapshot.getPath() + " doesn't exist"); -235 continue; -236 } -237 FSDataInputStream in = null; -238 try { -239 in = fs.open(info); -240 SnapshotDescription desc = SnapshotDescription.parseFrom(in); -241 org.apache.hadoop.hbase.client.SnapshotDescription descPOJO = (withCpCall) -242 ? ProtobufUtil.createSnapshotDesc(desc) : null; -243 if (withCpCall) { -244 try { -245 cpHost.preListSnapshot(descPOJO); -246 } catch (AccessDeniedException e) { -247 LOG.warn("Current user does not have access to " + desc.getName() + " snapshot. " -248 + "Either you should be owner of this snapshot or admin user."); -249 // Skip this and try for next snapshot -250 continue; -251 } -252 } -253 snapshotDescs.add(desc); -254 -255 // call coproc post hook -256 if (withCpCall) { -257 cpHost.postListSnapshot(descPOJO); -258 } -259 } catch (IOException e) { -260 LOG.warn("Found a corrupted snapshot " + snapshot.getPath(), e); -261 } finally { -262 if (in != null) { -263 in.close(); -264 } -265 } -266 } -267 return snapshotDescs; -268 } -269 -270 /** -271 * Cleans up any snapshots in the snapshot/.tmp directory that were left from failed -272 * snapshot attempts. -273 * -274 * @throws IOException if we can't reach the filesystem -275 */ -276 void resetTempDir() throws IOException { -277 // cleanup any existing snapshots. -278 Path tmpdir = SnapshotDescriptionUtils.getWorkingSnapshotDir(rootDir); -279 if (master.getMasterFileSystem().getFileSystem().exists(tmpdir)) { -280 if (!master.getMasterFileSystem().getFileSystem().delete(tmpdir, true)) { -281 LOG.warn("Couldn't delete working snapshot directory: " + tmpdir); -282 } -283 } -284 } -285 -286 /** -287 * Delete the specified snapshot -288 * @param snapshot -289 * @throws SnapshotDoesNotExistException If the specified snapshot does not exist. -290 * @throws IOException For filesystem IOExceptions -291 */ -292 public void deleteSnapshot(SnapshotDescription snapshot) throws SnapshotDoesNotExistException, IOException { -293 // check to see if it is completed -294 if (!isSnapshotCompleted(snapshot)) { -295 throw new SnapshotDoesNotExistException(ProtobufUtil.createSnapshotDesc(snapshot)); -296 } -297 -298 String snapshotName = snapshot.getName(); -299 // first create the snapshot description and check to see if it exists -300 FileSystem fs = master.getMasterFileSystem().getFileSystem(); -301 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir); -302 // Get snapshot info from file system. The one passed as parameter is a "fake" snapshotInfo with -303 // just the "name" and it does not contains the "real" snapshot information -304 snapshot = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir); -305 -306 // call coproc pre hook -307 MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); -308 org.apache.hadoop.hbase.client.SnapshotDescription snapshotPOJO = null; -309 if (cpHost != null) { -310 snapshotPOJO = ProtobufUtil.createSnapshotDesc(snapshot); -311 cpHost.preDeleteSnapshot(snapshotPOJO); -312 } -313 -314 LOG.debug("Deleting snapshot: " + snapshotName); -315 // delete the existing snapshot -316 if (!fs.delete(snapshotDir, true)) { -317 throw new HBaseSnapshotException("Failed to delete snapshot directory: " + snapshotDir); -318 } -319 -320 // call coproc post hook -321 if (cpHost != null) { -322 cpHost.postDeleteSnapshot(snapshotPOJO); -323 } -324 -325 } -326 -327 /** -328 * Check if the specified snapshot is done -329 * -330 * @param expected -331 * @return true if snapshot is ready to be restored, false if it is still being taken. -332 * @throws IOException IOException if error from HDFS or RPC -333 * @throws UnknownSnapshotException if snapshot is invalid or does not exist. -334 */ -335 public boolean isSnapshotDone(SnapshotDescription expected) throws IOException { -336 // check the request to make sure it has a snapshot -337 if (expected == null) { -338 throw new UnknownSnapshotException( -339 "No snapshot name passed in request, can't figure out which snapshot you want to check."); -340 } -341 -342 String ssString = ClientSnapshotDescriptionUtils.toString(expected); -343 -344 // check to see if the sentinel exists, -345 // and if the task is complete removes it from the in-progress snapshots map. -346 SnapshotSentinel handler = removeSentinelIfFinished(this.snapshotHandlers, expected); -347 -348 // stop tracking "abandoned" handlers -349 cleanupSentinels(); -350 -351 if (handler == null) { -352 // If there's no handler in the in-progress map, it means one of the following: -353 // - someone has already requested the snapshot state -354 // - the requested snapshot was completed long time ago (cleanupSentinels() timeout) -355 // - the snapshot was never requested -356 // In those cases returns to the user the "done state" if the snapshots exists on disk, -357 // otherwise raise an exception saying that the snapshot is not running and doesn't exist. -358 if (!isSnapshotCompleted(expected)) { -359 throw new UnknownSnapshotException("Snapshot " + ssString -360 + " is not currently running or one of the known completed snapshots."); -361 } -362 // was done, return true; -363 return true; -364 } -365 -366 // pass on any failure we find in the sentinel -367 try { -368 handler.rethrowExceptionIfFailed(); -369 } catch (ForeignException e) { -370 // Give some procedure info on an exception. -371 String status; -372 Procedure p = coordinator.getProcedure(expected.getName()); -373 if (p != null) { -374 status = p.getStatus(); -375 } else { -376 status = expected.getName() + " not found in proclist " + coordinator.getProcedureNames(); -377 } -378 throw new HBaseSnapshotException("Snapshot " + ssString + " had an error. " + status, e, -379 ProtobufUtil.createSnapshotDesc(expected)); -380 } -381 -382 // check to see if we are done -383 if (handler.isFinished()) { -384 LOG.debug("Snapshot '" + ssString + "' has completed, notifying client."); -385 return true; -386 } else if (LOG.isDebugEnabled()) { -387 LOG.debug("Snapshoting '" + ssString + "' is still in progress!"); -388 } -389 return false; -390 } -391 -392 /** -393 * Check to see if there is a snapshot in progress with the same name or on the same table. -394 * Currently we have a limitation only allowing a single snapshot per table at a time. Also we -395 * don't allow snapshot with the same name. -396 * @param snapshot description of the snapshot being checked. -397 * @return <tt>true</tt> if there is a snapshot in progress with the same name or on the same -398 * table. -399 */ -400 synchronized boolean isTakingSnapshot(final SnapshotDescription snapshot) { -401 TableName snapshotTable = TableName.valueOf(snapshot.getTable()); -402 if (isTakingSnapshot(snapshotTable)) { -403 return true; -404 } -405 Iterator<Map.Entry<TableName, SnapshotSentinel>> it = this.snapshotHandlers.entrySet().iterator(); -406 while (it.hasNext()) { -407 Map.Entry<TableName, SnapshotSentinel> entry = it.next(); -408 SnapshotSentinel sentinel = entry.getValue(); -409 if (snapshot.getName().equals(sentinel.getSnapshot().getName()) && !sentinel.isFinished()) { -410 return true; -411 } -412 } -413 return false; -414 } -415 -416 /** -417 * Check to see if the specified table has a snapshot in progress. Currently we have a -418 * limitation only allowing a single snapshot per table at a time. -419 * @param tableName name of the table being snapshotted. -420 * @return <tt>true</tt> if there is a snapshot in progress on the specified table. -421 */ -422 synchronized boolean isTakingSnapshot(final TableName tableName) { -423 SnapshotSentinel handler = this.snapshotHandlers.get(tableName); -424 return handler != null && !handler.isFinished(); -425 } -426 -427 /** -428 * Check to make sure that we are OK to run the passed snapshot. Checks to make sure that we -429 * aren't already running a snapshot or restore on the requested table. -430 * @param snapshot description of the snapshot we want to start -431 * @throws HBaseSnapshotException if the filesystem could not be prepared to start the snapshot -432 */ -433 private synchronized void prepareToTakeSnapshot(SnapshotDescription snapshot) -434 throws HBaseSnapshotException { -435 FileSystem fs = master.getMasterFileSystem().getFileSystem(); -436 Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir); -437 TableName snapshotTable = -438 TableName.valueOf(snapshot.getTable()); -439 -440 // make sure we aren't already running a snapshot -441 if (isTakingSnapshot(snapshot)) { -442 SnapshotSentinel handler = this.snapshotHandlers.get(snapshotTable); -443 throw new SnapshotCreationException("Rejected taking " -444 + ClientSnapshotDescriptionUtils.toString(snapshot) -445 + " because we are already running another snapshot " -446 + (handler != null ? ("on the same table " + -447 ClientSnapshotDescriptionUtils.toString(handler.getSnapshot())) -448 : "with the same name"), ProtobufUtil.createSnapshotDesc(snapshot)); -449 } -450 -451 // make sure we aren't running a restore on the same table -452 if (isRestoringTable(snapshotTable)) { -453 throw new SnapshotCreationException("Rejected taking " -454 + ClientSnapshotDescriptionUtils.toString(snapshot) -455 + " because we are already have a restore in progress on the same snapshot."); -456 } -457 -458 try { -459 // delete the working directory, since we aren't running the snapshot. Likely leftovers -460 // from a failed attempt. -461 fs.delete(workingDir, true); -462 -463 // recreate the working directory for the snapshot -464 if (!fs.mkdirs(workingDir)) { -465 throw new SnapshotCreationException( -466 "Couldn't create working directory (" + workingDir + ") for snapshot", -467 ProtobufUtil.createSnapshotDesc(snapshot)); -468 } -469 } catch (HBaseSnapshotException e) { -470 throw e; -471 } catch (IOException e) { -472 throw new SnapshotCreationException( -473 "Exception while checking to see if snapshot could be started.", e, -474 ProtobufUtil.createSnapshotDesc(snapshot)); -475 } -476 } -477 -478 /** -479 * Take a snapshot of a disabled table. -480 * @param snapshot description of the snapshot to take. Modified to be {@link Type#DISABLED}. -481 * @throws HBaseSnapshotException if the snapshot could not be started -482 */ -483 private synchronized void snapshotDisabledTable(SnapshotDescription snapshot) -484 throws HBaseSnapshotException { -485 // setup the snapshot -486 prepareToTakeSnapshot(snapshot); -487 -488 // set the snapshot to be a disabled snapshot, since the client doesn't know about that -489 snapshot = snapshot.toBuilder().setType(Type.DISABLED).build(); -490 -491 // Take the snapshot of the disabled table -492 DisabledTableSnapshotHandler handler = -493 new DisabledTableSnapshotHandler(snapshot, master, this); -494 snapshotTable(snapshot, handler); -495 } -496 -497 /** -498 * Take a snapshot of an enabled table. -499 * @param snapshot description of the snapshot to take. -500 * @throws HBaseSnapshotException if the snapshot could not be started -501 */ -502 private synchronized void snapshotEnabledTable(SnapshotDescription snapshot) -503 throws HBaseSnapshotException { -504 // setup the snapshot -505 prepareToTakeSnapshot(snapshot); -506 -507 // Take the snapshot of the enabled table -508 EnabledTableSnapshotHandler handler = -509 new EnabledTableSnapshotHandler(snapshot, master, this); -510 snapshotTable(snapshot, handler); -511 } -512 -513 /** -514 * Take a snapshot using the specified handler. -515 * On failure the snapshot temporary working directory is removed. -516 * NOTE: prepareToTakeSnapshot() called before this one takes care of the rejecting the -517 * snapshot request if the table is busy with another snapshot/restore operation. -518 * @param snapshot the snapshot description -519 * @param handler the snapshot handler -520 */ -521 private synchronized void snapshotTable(SnapshotDescription snapshot, -522 final TakeSnapshotHandler handler) throws HBaseSnapshotException { -523 try { -524 handler.prepare(); -525 this.executorService.submit(handler); -526 this.snapshotHandlers.put(TableName.valueOf(snapshot.getTable()), handler); -527 } catch (Exception e) { -528 // cleanup the working directory by trying to delete it from the fs. -529 Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir); -530 try { -531 if (!this.master.getMasterFileSystem().getFileSystem().delete(workingDir, true)) { -532 LOG.error("Couldn't delete working directory (" + workingDir + " for snapshot:" + -533 ClientSnapshotDescriptionUtils.toString(snapshot)); -534 } -535 } catch (IOException e1) { -536 LOG.error("Couldn't delete working directory (" + workingDir + " for snapshot:" + -537 ClientSnapshotDescriptionUtils.toString(snapshot)); -538 } -539 // fail the snapshot -540 throw new SnapshotCreationException("Could not build snapshot handler", e, -541 ProtobufUtil.createSnapshotDesc(snapshot)); -542 } -543 } -544 -545 /** -546 * Take a snapshot based on the enabled/disabled state of the table. -547 * -548 * @param snapshot -549 * @throws HBaseSnapshotException when a snapshot specific exception occurs. -550 * @throws IOException when some sort of generic IO exception occurs. -551 */ -552 public void takeSnapshot(SnapshotDescription snapshot) throws IOException { -553 // check to see if we already completed the snapshot -554 if (isSnapshotCompleted(snapshot)) { -555 throw new SnapshotExistsException( -556 "Snapshot '" + snapshot.getName() + "' already stored on the filesystem.", -557 ProtobufUtil.createSnapshotDesc(snapshot)); -558 } -559 -560 LOG.debug("No existing snapshot, attempting snapshot..."); -561 -562 // stop tracking "abandoned" handlers -563 cleanupSentinels(); -564 -565 // check to see if the table exists -566 TableDescriptor desc = null; -567 try { -568 desc = master.getTableDescriptors().get( -569 TableName.valueOf(snapshot.getTable())); -570 } catch (FileNotFoundException e) { -571 String msg = "Table:" + snapshot.getTable() + " info doesn't exist!"; -572 LOG.error(msg); -573 throw new SnapshotCreationException(msg, e, ProtobufUtil.createSnapshotDesc(snapshot)); -574 } catch (IOException e) { -575 throw new SnapshotCreationException( -576 "Error while geting table description for table " + snapshot.getTable(), e, -577 ProtobufUtil.createSnapshotDesc(snapshot)); -578 } -579 if (desc == null) { -580 throw new SnapshotCreationException( -581 "Table '" + snapshot.getTable() + "' doesn't exist, can't take snapshot.", -582 ProtobufUtil.createSnapshotDesc(snapshot)); -583 } -584 SnapshotDescription.Builder builder = snapshot.toBuilder(); -585 // if not specified, set the snapshot format -586 if (!snapshot.hasVersion()) { -587 builder.setVersion(SnapshotDescriptionUtils.SNAPSHOT_LAYOUT_VERSION); -588 } -589 User user = RpcServer.getRequestUser(); -590 if (User.isHBaseSecurityEnabled(master.getConfiguration()) && user != null) { -591 builder.setOwner(user.getShortName()); -592 } -593 snapshot = builder.build(); -594 -595 // call pre coproc hook -596 MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); -597 org.apache.hadoop.hbase.client.SnapshotDescription snapshotPOJO = null; -598 if (cpHost != null) { -599 snapshotPOJO = ProtobufUtil.createSnapshotDesc(snapshot); -600 cpHost.preSnapshot(snapshotPOJO, desc); -601 } -602 -603 // if the table is enabled, then have the RS run actually the snapshot work -604 TableName snapshotTable = TableName.valueOf(snapshot.getTable()); -605 if (master.getTableStateManager().isTableState(snapshotTable, -606 TableState.State.ENABLED)) { -607 LOG.debug("Table enabled, starting distributed snapshot."); -608 snapshotEnabledTable(snapshot); -609 LOG.debug("Started snapshot: " + ClientSnapshotDescriptionUtils.toString(snapshot)); -610 } -611 // For disabled table, snapshot is created by the master -612 else if (master.getTableStateManager().isTableState(snapshotTable, -613 TableState.State.DISABLED)) { -614 LOG.debug("Table is disabled, running snapshot entirely on master."); -615 snapshotDisabledTable(snapshot); -616 LOG.debug("Started snapshot: " + ClientSnapshotDescriptionUtils.toString(snapshot)); -617 } else { -618 LOG.error("Can't snapshot table '" + snapshot.getTable() -619 + "', isn't open or closed, we don't know what to do!"); -620 TablePartiallyOpenException tpoe = new TablePartiallyOpenException(snapshot.getTable() -621 + " isn't fully open."); -622 throw new SnapshotCreationException("Table is not entirely open or closed", tpoe, -623 ProtobufUtil.createSnapshotDesc(snapshot)); -624 } -625 -626 // call post coproc hook -627 if (cpHost != null) { -628 cpHost.postSnapshot(snapshotPOJO, desc); -629 } -630 } -631 -632 /** -633 * Set the handler for the current snapshot -634 * <p> -635 * Exposed for TESTING -636 * @param tableName -637 * @param handler handler the master should use -638 * -639 * TODO get rid of this if possible, repackaging, modify tests. -640 */ -641 public synchronized void setSnapshotHandlerForTesting( -642 final TableName tableName, -643 final SnapshotSentinel handler) { -644 if (handler != null) { -645 this.snapshotHandlers.put(tableName, handler); -646 } else { -647 this.snapshotHandlers.remove(tableName); -648 } -649 } -650 -651 /** -652 * @return distributed commit coordinator for all running snapshots -653 */ -654 ProcedureCoordinator getCoordinator() { -655 return coordinator; -656 } -657 -658 /** -659 * Check to see if the snapshot is one of the currently completed snapshots -660 * Returns true if the snapshot exists in the "completed snapshots folder". -661 * -662 * @param snapshot expected snapshot to check -663 * @return <tt>true</tt> if the snapshot is stored on the {@link FileSystem}, <tt>false</tt> if is -664 * not stored -665 * @throws IOException if the filesystem throws an unexpected exception, -666 * @throws IllegalArgumentException if snapshot name is invalid. -667 */ -668 private boolean isSnapshotCompleted(SnapshotDescription snapshot) throws IOException { -669 try { -670 final Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir); -671 FileSystem fs = master.getMasterFileSystem().getFileSystem(); -672 // check to see if the snapshot already exists -673 return fs.exists(snapshotDir); -674 } catch (IllegalArgumentException iae) { -675 throw new UnknownSnapshotException("Unexpected exception thrown", iae); -676 } -677 } -678 -679 /** -680 * Clone the specified snapshot. -681 * The clone will fail if the destination table has a snapshot or restore in progress. -682 * -683 * @param reqSnapshot Snapshot Descriptor from request -684 * @param tableName table to clone -685 * @param snapshot Snapshot Descriptor -686 * @param snapshotTableDesc Table Descriptor -687 * @param nonceKey unique identifier to prevent duplicated RPC -688 * @return procId the ID of the clone snapshot procedure -689 * @throws IOException -690 */ -691 private long cloneSnapshot(final SnapshotDescription reqSnapshot, final TableName tableName, -692 final SnapshotDescription snapshot, final TableDescriptor snapshotTableDesc, -693 final NonceKey nonceKey, final boolean restoreAcl) throws IOException { -694 MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); -695 TableDescriptor htd = TableDescriptorBuilder.copy(tableName, snapshotTableDesc); -696 org.apache.hadoop.hbase.client.SnapshotDescription snapshotPOJO = null; -697 if (cpHost != null) { -698 snapshotPOJO = ProtobufUtil.createSnapshotDesc(reqSnapshot); -699 cpHost.preCloneSnapshot(snapshotPOJO, htd); -700 } -701 long procId; -702 try { -703 procId = cloneSnapshot(snapshot, htd, nonceKey, restoreAcl); -704 } catch (IOException e) { -705 LOG.error("Exception occurred while cloning the snapshot " + snapshot.getName() -706 + " as table " + tableName.getNameAsString(), e); -707 throw e; -708 } -709 LOG.info("Clone snapshot=" + snapshot.getName() + " as table=" + tableName); -710 -711 if (cpHost != null) { -712 cpHost.postCloneSnapshot(snapshotPOJO, htd); -713 } -714 return procId; -715 } -716 -717 /** -718 * Clone the specified snapshot into a new table. -719 * The operation will fail if the destination table has a snapshot or restore in progress. -720 * -721 * @param snapshot Snapshot Descriptor -722 * @param tableDescriptor Table Descriptor of the table to create -723 * @param nonceKey unique identifier to prevent duplicated RPC -724 * @return procId the ID of the clone snapshot procedure -725 */ -726 synchronized long cloneSnapshot(final SnapshotDescription snapshot, -727 final TableDescriptor tableDescriptor, final NonceKey nonceKey, final boolean restoreAcl) -728 throws HBaseSnapshotException { -729 TableName tableName = tableDescriptor.getTableName(); -730 -731 // make sure we aren't running a snapshot on the same table -732 if (isTakingSnapshot(tableName)) { -733 throw new RestoreSnapshotException("Snapshot in progress on the restore table=" + tableName); -734 } -735 -736 // make sure we aren't running a restore on the same table -737 if (isRestoringTable(tableName)) { -738 throw new RestoreSnapshotException("Restore already in progress on the table=" + tableName); -739 } -740 -741 try { -742 long procId = master.getMasterProcedureExecutor().submitProcedure( -743 new CloneSnapshotProcedure(master.getMasterProcedureExecutor().getEnvironment(), -744 tableDescriptor, snapshot, restoreAcl), -745 nonceKey); -746 this.restoreTableToProcIdMap.put(tableName, procId); -747 return procId; -748 } catch (Exception e) { -749 String msg = "Couldn't clone the snapshot=" -750 + ClientSnapshotDescriptionUtils.toString(snapshot) + " on table=" + tableName; -751 LOG.error(msg, e); -752 throw new RestoreSnapshotException(msg, e); -753 } -754 }