Esempio n. 1
0
  /**
   * Check if the specified snapshot is done
   *
   * @param expected
   * @return true if snapshot is ready to be restored, false if it is still being taken.
   * @throws IOException IOException if error from HDFS or RPC
   * @throws UnknownSnapshotException if snapshot is invalid or does not exist.
   */
  public boolean isSnapshotDone(SnapshotDescription expected) throws IOException {
    // check the request to make sure it has a snapshot
    if (expected == null) {
      throw new UnknownSnapshotException(
          "No snapshot name passed in request, can't figure out which snapshot you want to check.");
    }

    String ssString = ClientSnapshotDescriptionUtils.toString(expected);

    // check to see if the sentinel exists,
    // and if the task is complete removes it from the in-progress snapshots map.
    SnapshotSentinel handler = removeSentinelIfFinished(this.snapshotHandlers, expected);

    // stop tracking "abandoned" handlers
    cleanupSentinels();

    if (handler == null) {
      // If there's no handler in the in-progress map, it means one of the following:
      //   - someone has already requested the snapshot state
      //   - the requested snapshot was completed long time ago (cleanupSentinels() timeout)
      //   - the snapshot was never requested
      // In those cases returns to the user the "done state" if the snapshots exists on disk,
      // otherwise raise an exception saying that the snapshot is not running and doesn't exist.
      if (!isSnapshotCompleted(expected)) {
        throw new UnknownSnapshotException(
            "Snapshot "
                + ssString
                + " is not currently running or one of the known completed snapshots.");
      }
      // was done, return true;
      return true;
    }

    // pass on any failure we find in the sentinel
    try {
      handler.rethrowExceptionIfFailed();
    } catch (ForeignException e) {
      // Give some procedure info on an exception.
      String status;
      Procedure p = coordinator.getProcedure(expected.getName());
      if (p != null) {
        status = p.getStatus();
      } else {
        status = expected.getName() + " not found in proclist " + coordinator.getProcedureNames();
      }
      throw new HBaseSnapshotException(
          "Snapshot " + ssString + " had an error.  " + status,
          e,
          ProtobufUtil.createSnapshotDesc(expected));
    }

    // check to see if we are done
    if (handler.isFinished()) {
      LOG.debug("Snapshot '" + ssString + "' has completed, notifying client.");
      return true;
    } else if (LOG.isDebugEnabled()) {
      LOG.debug("Snapshoting '" + ssString + "' is still in progress!");
    }
    return false;
  }
Esempio n. 2
0
 /**
  * Remove the sentinels that are marked as finished and the completion time has exceeded the
  * removal timeout.
  *
  * @param sentinels map of sentinels to clean
  */
 private synchronized void cleanupSentinels(final Map<TableName, SnapshotSentinel> sentinels) {
   long currentTime = EnvironmentEdgeManager.currentTime();
   Iterator<Map.Entry<TableName, SnapshotSentinel>> it = sentinels.entrySet().iterator();
   while (it.hasNext()) {
     Map.Entry<TableName, SnapshotSentinel> entry = it.next();
     SnapshotSentinel sentinel = entry.getValue();
     if (sentinel.isFinished()
         && (currentTime - sentinel.getCompletionTimestamp())
             > SNAPSHOT_SENTINELS_CLEANUP_TIMEOUT) {
       it.remove();
     }
   }
 }
Esempio n. 3
0
  /**
   * Check to make sure that we are OK to run the passed snapshot. Checks to make sure that we
   * aren't already running a snapshot or restore on the requested table.
   *
   * @param snapshot description of the snapshot we want to start
   * @throws HBaseSnapshotException if the filesystem could not be prepared to start the snapshot
   */
  private synchronized void prepareToTakeSnapshot(SnapshotDescription snapshot)
      throws HBaseSnapshotException {
    FileSystem fs = master.getMasterFileSystem().getFileSystem();
    Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir);
    TableName snapshotTable = TableName.valueOf(snapshot.getTable());

    // make sure we aren't already running a snapshot
    if (isTakingSnapshot(snapshot)) {
      SnapshotSentinel handler = this.snapshotHandlers.get(snapshotTable);
      throw new SnapshotCreationException(
          "Rejected taking "
              + ClientSnapshotDescriptionUtils.toString(snapshot)
              + " because we are already running another snapshot "
              + (handler != null
                  ? ("on the same table "
                      + ClientSnapshotDescriptionUtils.toString(handler.getSnapshot()))
                  : "with the same name"),
          ProtobufUtil.createSnapshotDesc(snapshot));
    }

    // make sure we aren't running a restore on the same table
    if (isRestoringTable(snapshotTable)) {
      throw new SnapshotCreationException(
          "Rejected taking "
              + ClientSnapshotDescriptionUtils.toString(snapshot)
              + " because we are already have a restore in progress on the same snapshot.");
    }

    try {
      // delete the working directory, since we aren't running the snapshot. Likely leftovers
      // from a failed attempt.
      fs.delete(workingDir, true);

      // recreate the working directory for the snapshot
      if (!fs.mkdirs(workingDir)) {
        throw new SnapshotCreationException(
            "Couldn't create working directory (" + workingDir + ") for snapshot",
            ProtobufUtil.createSnapshotDesc(snapshot));
      }
    } catch (HBaseSnapshotException e) {
      throw e;
    } catch (IOException e) {
      throw new SnapshotCreationException(
          "Exception while checking to see if snapshot could be started.",
          e,
          ProtobufUtil.createSnapshotDesc(snapshot));
    }
  }
Esempio n. 4
0
 /**
  * Check to see if there is a snapshot in progress with the same name or on the same table.
  * Currently we have a limitation only allowing a single snapshot per table at a time. Also we
  * don't allow snapshot with the same name.
  *
  * @param snapshot description of the snapshot being checked.
  * @return <tt>true</tt> if there is a snapshot in progress with the same name or on the same
  *     table.
  */
 synchronized boolean isTakingSnapshot(final SnapshotDescription snapshot) {
   TableName snapshotTable = TableName.valueOf(snapshot.getTable());
   if (isTakingSnapshot(snapshotTable)) {
     return true;
   }
   Iterator<Map.Entry<TableName, SnapshotSentinel>> it =
       this.snapshotHandlers.entrySet().iterator();
   while (it.hasNext()) {
     Map.Entry<TableName, SnapshotSentinel> entry = it.next();
     SnapshotSentinel sentinel = entry.getValue();
     if (snapshot.getName().equals(sentinel.getSnapshot().getName()) && !sentinel.isFinished()) {
       return true;
     }
   }
   return false;
 }
Esempio n. 5
0
  @Override
  public void stop(String why) {
    // short circuit
    if (this.stopped) return;
    // make sure we get stop
    this.stopped = true;
    // pass the stop onto take snapshot handlers
    for (SnapshotSentinel snapshotHandler : this.snapshotHandlers.values()) {
      snapshotHandler.cancel(why);
    }

    try {
      if (coordinator != null) {
        coordinator.close();
      }
    } catch (IOException e) {
      LOG.error("stop ProcedureCoordinator error", e);
    }
  }
Esempio n. 6
0
  /**
   * Return the handler if it is currently live and has the same snapshot target name. The handler
   * is removed from the sentinels map if completed.
   *
   * @param sentinels live handlers
   * @param snapshot snapshot description
   * @return null if doesn't match, else a live handler.
   */
  private synchronized SnapshotSentinel removeSentinelIfFinished(
      final Map<TableName, SnapshotSentinel> sentinels, final SnapshotDescription snapshot) {
    if (!snapshot.hasTable()) {
      return null;
    }

    TableName snapshotTable = TableName.valueOf(snapshot.getTable());
    SnapshotSentinel h = sentinels.get(snapshotTable);
    if (h == null) {
      return null;
    }

    if (!h.getSnapshot().getName().equals(snapshot.getName())) {
      // specified snapshot is to the one currently running
      return null;
    }

    // Remove from the "in-progress" list once completed
    if (h.isFinished()) {
      sentinels.remove(snapshotTable);
    }

    return h;
  }
Esempio n. 7
0
 /**
  * Check to see if the specified table has a snapshot in progress. Currently we have a limitation
  * only allowing a single snapshot per table at a time.
  *
  * @param tableName name of the table being snapshotted.
  * @return <tt>true</tt> if there is a snapshot in progress on the specified table.
  */
 synchronized boolean isTakingSnapshot(final TableName tableName) {
   SnapshotSentinel handler = this.snapshotHandlers.get(tableName);
   return handler != null && !handler.isFinished();
 }