/**
  * Remove the snapshot with the given name from {@link #snapshotsByNames}, and delete all the
  * corresponding DirectoryDiff.
  *
  * @param snapshotName The name of the snapshot to be removed
  * @param collectedBlocks Used to collect information to update blocksMap
  * @return The removed snapshot. Null if no snapshot with the given name exists.
  */
 Snapshot removeSnapshot(
     String snapshotName, BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes)
     throws SnapshotException {
   final int i = searchSnapshot(DFSUtil.string2Bytes(snapshotName));
   if (i < 0) {
     throw new SnapshotException(
         "Cannot delete snapshot "
             + snapshotName
             + " from path "
             + this.getFullPathName()
             + ": the snapshot does not exist.");
   } else {
     final Snapshot snapshot = snapshotsByNames.get(i);
     Snapshot prior = Snapshot.findLatestSnapshot(this, snapshot);
     try {
       Quota.Counts counts = cleanSubtree(snapshot, prior, collectedBlocks, removedINodes, true);
       INodeDirectory parent = getParent();
       if (parent != null) {
         // there will not be any WithName node corresponding to the deleted
         // snapshot, thus only update the quota usage in the current tree
         parent.addSpaceConsumed(-counts.get(Quota.NAMESPACE), -counts.get(Quota.DISKSPACE), true);
       }
     } catch (QuotaExceededException e) {
       LOG.error("BUG: removeSnapshot increases namespace usage.", e);
     }
     // remove from snapshotsByNames after successfully cleaning the subtree
     snapshotsByNames.remove(i);
     return snapshot;
   }
 }