/** * Clone the specified snapshot. The clone will fail if the destination table has a snapshot or * restore in progress. * * @param reqSnapshot Snapshot Descriptor from request * @param tableName table to clone * @param snapshot Snapshot Descriptor * @param snapshotTableDesc Table Descriptor * @param nonceGroup unique value to prevent duplicated RPC * @param nonce unique value to prevent duplicated RPC * @return procId the ID of the clone snapshot procedure * @throws IOException */ private long cloneSnapshot( final SnapshotDescription reqSnapshot, final TableName tableName, final SnapshotDescription snapshot, final HTableDescriptor snapshotTableDesc, final long nonceGroup, final long nonce) throws IOException { MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); HTableDescriptor htd = new HTableDescriptor(tableName, snapshotTableDesc); if (cpHost != null) { cpHost.preCloneSnapshot(reqSnapshot, htd); } long procId; try { procId = cloneSnapshot(snapshot, htd, nonceGroup, nonce); } catch (IOException e) { LOG.error( "Exception occurred while cloning the snapshot " + snapshot.getName() + " as table " + tableName.getNameAsString(), e); throw e; } LOG.info("Clone snapshot=" + snapshot.getName() + " as table=" + tableName); if (cpHost != null) { cpHost.postCloneSnapshot(reqSnapshot, htd); } return procId; }
/** * Delete the specified snapshot * * @param snapshot * @throws SnapshotDoesNotExistException If the specified snapshot does not exist. * @throws IOException For filesystem IOExceptions */ public void deleteSnapshot(SnapshotDescription snapshot) throws SnapshotDoesNotExistException, IOException { // check to see if it is completed if (!isSnapshotCompleted(snapshot)) { throw new SnapshotDoesNotExistException(ProtobufUtil.createSnapshotDesc(snapshot)); } String snapshotName = snapshot.getName(); // first create the snapshot description and check to see if it exists FileSystem fs = master.getMasterFileSystem().getFileSystem(); Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir); // Get snapshot info from file system. The one passed as parameter is a "fake" snapshotInfo with // just the "name" and it does not contains the "real" snapshot information snapshot = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir); // call coproc pre hook MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); if (cpHost != null) { cpHost.preDeleteSnapshot(snapshot); } LOG.debug("Deleting snapshot: " + snapshotName); // delete the existing snapshot if (!fs.delete(snapshotDir, true)) { throw new HBaseSnapshotException("Failed to delete snapshot directory: " + snapshotDir); } // call coproc post hook if (cpHost != null) { cpHost.postDeleteSnapshot(snapshot); } }
/** * Gets the list of all completed snapshots. * * @param snapshotDir snapshot directory * @return list of SnapshotDescriptions * @throws IOException File system exception */ private List<SnapshotDescription> getCompletedSnapshots(Path snapshotDir) throws IOException { List<SnapshotDescription> snapshotDescs = new ArrayList<SnapshotDescription>(); // first create the snapshot root path and check to see if it exists FileSystem fs = master.getMasterFileSystem().getFileSystem(); if (snapshotDir == null) snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir); // if there are no snapshots, return an empty list if (!fs.exists(snapshotDir)) { return snapshotDescs; } // ignore all the snapshots in progress FileStatus[] snapshots = fs.listStatus( snapshotDir, new SnapshotDescriptionUtils.CompletedSnaphotDirectoriesFilter(fs)); MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); // loop through all the completed snapshots for (FileStatus snapshot : snapshots) { Path info = new Path(snapshot.getPath(), SnapshotDescriptionUtils.SNAPSHOTINFO_FILE); // if the snapshot is bad if (!fs.exists(info)) { LOG.error("Snapshot information for " + snapshot.getPath() + " doesn't exist"); continue; } FSDataInputStream in = null; try { in = fs.open(info); SnapshotDescription desc = SnapshotDescription.parseFrom(in); if (cpHost != null) { try { cpHost.preListSnapshot(desc); } catch (AccessDeniedException e) { LOG.warn( "Current user does not have access to " + desc.getName() + " snapshot. " + "Either you should be owner of this snapshot or admin user."); // Skip this and try for next snapshot continue; } } snapshotDescs.add(desc); // call coproc post hook if (cpHost != null) { cpHost.postListSnapshot(desc); } } catch (IOException e) { LOG.warn("Found a corrupted snapshot " + snapshot.getPath(), e); } finally { if (in != null) { in.close(); } } } return snapshotDescs; }
/** * Restore the specified snapshot. The restore will fail if the destination table has a snapshot * or restore in progress. * * @param reqSnapshot Snapshot Descriptor from request * @param tableName table to restore * @param snapshot Snapshot Descriptor * @param snapshotTableDesc Table Descriptor * @param nonceGroup unique value to prevent duplicated RPC * @param nonce unique value to prevent duplicated RPC * @return procId the ID of the restore snapshot procedure * @throws IOException */ private long restoreSnapshot( final SnapshotDescription reqSnapshot, final TableName tableName, final SnapshotDescription snapshot, final HTableDescriptor snapshotTableDesc, final long nonceGroup, final long nonce) throws IOException { MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); if (master .getTableStateManager() .isTableState(TableName.valueOf(snapshot.getTable()), TableState.State.ENABLED)) { throw new UnsupportedOperationException( "Table '" + TableName.valueOf(snapshot.getTable()) + "' must be disabled in order to " + "perform a restore operation."); } // call Coprocessor pre hook if (cpHost != null) { cpHost.preRestoreSnapshot(reqSnapshot, snapshotTableDesc); } long procId; try { procId = restoreSnapshot(snapshot, snapshotTableDesc, nonceGroup, nonce); } catch (IOException e) { LOG.error( "Exception occurred while restoring the snapshot " + snapshot.getName() + " as table " + tableName.getNameAsString(), e); throw e; } LOG.info("Restore snapshot=" + snapshot.getName() + " as table=" + tableName); if (cpHost != null) { cpHost.postRestoreSnapshot(reqSnapshot, snapshotTableDesc); } return procId; }
/** * Take a snapshot based on the enabled/disabled state of the table. * * @param snapshot * @throws HBaseSnapshotException when a snapshot specific exception occurs. * @throws IOException when some sort of generic IO exception occurs. */ public void takeSnapshot(SnapshotDescription snapshot) throws IOException { // check to see if we already completed the snapshot if (isSnapshotCompleted(snapshot)) { throw new SnapshotExistsException( "Snapshot '" + snapshot.getName() + "' already stored on the filesystem.", ProtobufUtil.createSnapshotDesc(snapshot)); } LOG.debug("No existing snapshot, attempting snapshot..."); // stop tracking "abandoned" handlers cleanupSentinels(); // check to see if the table exists HTableDescriptor desc = null; try { desc = master.getTableDescriptors().get(TableName.valueOf(snapshot.getTable())); } catch (FileNotFoundException e) { String msg = "Table:" + snapshot.getTable() + " info doesn't exist!"; LOG.error(msg); throw new SnapshotCreationException(msg, e, ProtobufUtil.createSnapshotDesc(snapshot)); } catch (IOException e) { throw new SnapshotCreationException( "Error while geting table description for table " + snapshot.getTable(), e, ProtobufUtil.createSnapshotDesc(snapshot)); } if (desc == null) { throw new SnapshotCreationException( "Table '" + snapshot.getTable() + "' doesn't exist, can't take snapshot.", ProtobufUtil.createSnapshotDesc(snapshot)); } SnapshotDescription.Builder builder = snapshot.toBuilder(); // if not specified, set the snapshot format if (!snapshot.hasVersion()) { builder.setVersion(SnapshotDescriptionUtils.SNAPSHOT_LAYOUT_VERSION); } User user = RpcServer.getRequestUser(); if (User.isHBaseSecurityEnabled(master.getConfiguration()) && user != null) { builder.setOwner(user.getShortName()); } snapshot = builder.build(); // call pre coproc hook MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); if (cpHost != null) { cpHost.preSnapshot(snapshot, desc); } // if the table is enabled, then have the RS run actually the snapshot work TableName snapshotTable = TableName.valueOf(snapshot.getTable()); if (master.getTableStateManager().isTableState(snapshotTable, TableState.State.ENABLED)) { LOG.debug("Table enabled, starting distributed snapshot."); snapshotEnabledTable(snapshot); LOG.debug("Started snapshot: " + ClientSnapshotDescriptionUtils.toString(snapshot)); } // For disabled table, snapshot is created by the master else if (master.getTableStateManager().isTableState(snapshotTable, TableState.State.DISABLED)) { LOG.debug("Table is disabled, running snapshot entirely on master."); snapshotDisabledTable(snapshot); LOG.debug("Started snapshot: " + ClientSnapshotDescriptionUtils.toString(snapshot)); } else { LOG.error( "Can't snapshot table '" + snapshot.getTable() + "', isn't open or closed, we don't know what to do!"); TablePartiallyOpenException tpoe = new TablePartiallyOpenException(snapshot.getTable() + " isn't fully open."); throw new SnapshotCreationException( "Table is not entirely open or closed", tpoe, ProtobufUtil.createSnapshotDesc(snapshot)); } // call post coproc hook if (cpHost != null) { cpHost.postSnapshot(snapshot, desc); } }