/** Cast INode to INodeDirectorySnapshottable. */
 public static INodeDirectorySnapshottable valueOf(INode inode, String src) throws IOException {
   final INodeDirectory dir = INodeDirectory.valueOf(inode, src);
   if (!dir.isSnapshottable()) {
     throw new SnapshotException("Directory is not a snapshottable directory: " + src);
   }
   return (INodeDirectorySnapshottable) dir;
 }
 /**
  * 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;
   }
 }
 /**
  * Recursively compute the difference between snapshots under a given directory/file.
  *
  * @param node The directory/file under which the diff is computed.
  * @param parentPath Relative path (corresponding to the snapshot root) of the node's parent.
  * @param diffReport data structure used to store the diff.
  */
 private void computeDiffRecursively(
     INode node, List<byte[]> parentPath, SnapshotDiffInfo diffReport) {
   ChildrenDiff diff = new ChildrenDiff();
   byte[][] relativePath = parentPath.toArray(new byte[parentPath.size()][]);
   if (node.isDirectory()) {
     INodeDirectory dir = node.asDirectory();
     if (dir instanceof INodeDirectoryWithSnapshot) {
       INodeDirectoryWithSnapshot sdir = (INodeDirectoryWithSnapshot) dir;
       boolean change = sdir.computeDiffBetweenSnapshots(diffReport.from, diffReport.to, diff);
       if (change) {
         diffReport.addDirDiff(sdir, relativePath, diff);
       }
     }
     ReadOnlyList<INode> children =
         dir.getChildrenList(diffReport.isFromEarlier() ? diffReport.to : diffReport.from);
     for (INode child : children) {
       final byte[] name = child.getLocalNameBytes();
       if (diff.searchIndex(ListType.CREATED, name) < 0
           && diff.searchIndex(ListType.DELETED, name) < 0) {
         parentPath.add(name);
         computeDiffRecursively(child, parentPath, diffReport);
         parentPath.remove(parentPath.size() - 1);
       }
     }
   } else if (node.isFile() && node.asFile() instanceof FileWithSnapshot) {
     FileWithSnapshot file = (FileWithSnapshot) node.asFile();
     Snapshot earlierSnapshot = diffReport.isFromEarlier() ? diffReport.from : diffReport.to;
     Snapshot laterSnapshot = diffReport.isFromEarlier() ? diffReport.to : diffReport.from;
     boolean change = file.getDiffs().changedBetweenSnapshots(earlierSnapshot, laterSnapshot);
     if (change) {
       diffReport.addFileDiff(file.asINodeFile(), relativePath);
     }
   }
 }
 /**
  * Rename a snapshot
  *
  * @param path The directory path where the snapshot was taken. Used for generating exception
  *     message.
  * @param oldName Old name of the snapshot
  * @param newName New name the snapshot will be renamed to
  * @throws SnapshotException Throw SnapshotException when either the snapshot with the old name
  *     does not exist or a snapshot with the new name already exists
  */
 public void renameSnapshot(String path, String oldName, String newName) throws SnapshotException {
   if (newName.equals(oldName)) {
     return;
   }
   final int indexOfOld = searchSnapshot(DFSUtil.string2Bytes(oldName));
   if (indexOfOld < 0) {
     throw new SnapshotException(
         "The snapshot " + oldName + " does not exist for directory " + path);
   } else {
     final byte[] newNameBytes = DFSUtil.string2Bytes(newName);
     int indexOfNew = searchSnapshot(newNameBytes);
     if (indexOfNew > 0) {
       throw new SnapshotException(
           "The snapshot " + newName + " already exists for directory " + path);
     }
     // remove the one with old name from snapshotsByNames
     Snapshot snapshot = snapshotsByNames.remove(indexOfOld);
     final INodeDirectory ssRoot = snapshot.getRoot();
     ssRoot.setLocalName(newNameBytes);
     indexOfNew = -indexOfNew - 1;
     if (indexOfNew <= indexOfOld) {
       snapshotsByNames.add(indexOfNew, snapshot);
     } else { // indexOfNew > indexOfOld
       snapshotsByNames.add(indexOfNew - 1, snapshot);
     }
   }
 }
Example #5
0
 /**
  * Find the latest snapshot that 1) covers the given inode (which means the snapshot was either
  * taken on the inode or taken on an ancestor of the inode), and 2) was taken before the given
  * snapshot (if the given snapshot is not null).
  *
  * @param inode the given inode that the returned snapshot needs to cover
  * @param anchor the returned snapshot should be taken before this given id.
  * @return id of the latest snapshot that covers the given inode and was taken before the the
  *     given snapshot (if it is not null).
  */
 public static int findLatestSnapshot(INode inode, final int anchor) {
   int latest = NO_SNAPSHOT_ID;
   for (; inode != null; inode = inode.getParent()) {
     if (inode.isDirectory()) {
       final INodeDirectory dir = inode.asDirectory();
       if (dir.isWithSnapshot()) {
         latest = dir.getDiffs().updatePrior(anchor, latest);
       }
     }
   }
   return latest;
 }
 private void loadSnapshots(InputStream in, int size) throws IOException {
   for (int i = 0; i < size; i++) {
     SnapshotSection.Snapshot pbs = SnapshotSection.Snapshot.parseDelimitedFrom(in);
     INodeDirectory root = loadINodeDirectory(pbs.getRoot(), parent.getLoaderContext());
     int sid = pbs.getSnapshotId();
     INodeDirectorySnapshottable parent =
         (INodeDirectorySnapshottable) fsDir.getInode(root.getId()).asDirectory();
     Snapshot snapshot = new Snapshot(sid, root, parent);
     // add the snapshot to parent, since we follow the sequence of
     // snapshotsByNames when saving, we do not need to sort when loading
     parent.addSnapshot(snapshot);
     snapshotMap.put(sid, snapshot);
   }
 }
 private void serializeDirDiffList(
     INodeDirectory dir, final List<INodeReference> refList, OutputStream out)
     throws IOException {
   DirectoryWithSnapshotFeature sf = dir.getDirectoryWithSnapshotFeature();
   if (sf != null) {
     List<DirectoryDiff> diffList = sf.getDiffs().asList();
     SnapshotDiffSection.DiffEntry entry =
         SnapshotDiffSection.DiffEntry.newBuilder()
             .setInodeId(dir.getId())
             .setType(Type.DIRECTORYDIFF)
             .setNumOfDiff(diffList.size())
             .build();
     entry.writeDelimitedTo(out);
     for (int i = diffList.size() - 1; i >= 0; i--) { // reverse order!
       DirectoryDiff diff = diffList.get(i);
       SnapshotDiffSection.DirectoryDiff.Builder db =
           SnapshotDiffSection.DirectoryDiff.newBuilder()
               .setSnapshotId(diff.getSnapshotId())
               .setChildrenSize(diff.getChildrenSize())
               .setIsSnapshotRoot(diff.isSnapshotRoot());
       INodeDirectoryAttributes copy = diff.snapshotINode;
       if (!diff.isSnapshotRoot() && copy != null) {
         db.setName(ByteString.copyFrom(copy.getLocalNameBytes()))
             .setSnapshotCopy(buildINodeDirectory(copy, parent.getSaverContext()));
       }
       // process created list and deleted list
       List<INode> created = diff.getChildrenDiff().getList(ListType.CREATED);
       db.setCreatedListSize(created.size());
       List<INode> deleted = diff.getChildrenDiff().getList(ListType.DELETED);
       for (INode d : deleted) {
         if (d.isReference()) {
           refList.add(d.asReference());
           db.addDeletedINodeRef(refList.size() - 1);
         } else {
           db.addDeletedINode(d.getId());
         }
       }
       db.build().writeDelimitedTo(out);
       saveCreatedList(created, out);
     }
   }
 }
 /**
  * Load the snapshots section from fsimage. Also convert snapshottable directories into {@link
  * INodeDirectorySnapshottable}.
  */
 public void loadSnapshotSection(InputStream in) throws IOException {
   SnapshotManager sm = fsn.getSnapshotManager();
   SnapshotSection section = SnapshotSection.parseDelimitedFrom(in);
   int snum = section.getNumSnapshots();
   sm.setNumSnapshots(snum);
   sm.setSnapshotCounter(section.getSnapshotCounter());
   for (long sdirId : section.getSnapshottableDirList()) {
     INodeDirectory dir = fsDir.getInode(sdirId).asDirectory();
     final INodeDirectorySnapshottable sdir;
     if (!dir.isSnapshottable()) {
       sdir = new INodeDirectorySnapshottable(dir);
       fsDir.addToInodeMap(sdir);
     } else {
       // dir is root, and admin set root to snapshottable before
       sdir = (INodeDirectorySnapshottable) dir;
       sdir.setSnapshotQuota(INodeDirectorySnapshottable.SNAPSHOT_LIMIT);
     }
     sm.addSnapshottable(sdir);
   }
   loadSnapshots(in, snum);
 }
Example #9
0
    Root(INodeDirectory other) {
      // Always preserve ACL, XAttr.
      super(
          other,
          false,
          Lists.newArrayList(
                  Iterables.filter(
                      Arrays.asList(other.getFeatures()),
                      new Predicate<Feature>() {

                        @Override
                        public boolean apply(Feature input) {
                          if (AclFeature.class.isInstance(input)
                              || XAttrFeature.class.isInstance(input)) {
                            return true;
                          }
                          return false;
                        }
                      }))
              .toArray(new Feature[0]));
    }
    /** Load DirectoryDiff list for a directory with snapshot feature */
    private void loadDirectoryDiffList(
        InputStream in, INodeDirectory dir, int size, final List<INodeReference> refList)
        throws IOException {
      if (!dir.isWithSnapshot()) {
        dir.addSnapshotFeature(null);
      }
      DirectoryDiffList diffs = dir.getDiffs();
      final LoaderContext state = parent.getLoaderContext();

      for (int i = 0; i < size; i++) {
        // load a directory diff
        SnapshotDiffSection.DirectoryDiff diffInPb =
            SnapshotDiffSection.DirectoryDiff.parseDelimitedFrom(in);
        final int snapshotId = diffInPb.getSnapshotId();
        final Snapshot snapshot = snapshotMap.get(snapshotId);
        int childrenSize = diffInPb.getChildrenSize();
        boolean useRoot = diffInPb.getIsSnapshotRoot();
        INodeDirectoryAttributes copy = null;
        if (useRoot) {
          copy = snapshot.getRoot();
        } else if (diffInPb.hasSnapshotCopy()) {
          INodeSection.INodeDirectory dirCopyInPb = diffInPb.getSnapshotCopy();
          final byte[] name = diffInPb.getName().toByteArray();
          PermissionStatus permission =
              loadPermission(dirCopyInPb.getPermission(), state.getStringTable());
          AclFeature acl = null;
          if (dirCopyInPb.hasAcl()) {
            acl =
                new AclFeature(
                    FSImageFormatPBINode.Loader.loadAclEntries(
                        dirCopyInPb.getAcl(), state.getStringTable()));
          }

          long modTime = dirCopyInPb.getModificationTime();
          boolean noQuota = dirCopyInPb.getNsQuota() == -1 && dirCopyInPb.getDsQuota() == -1;

          copy =
              noQuota
                  ? new INodeDirectoryAttributes.SnapshotCopy(name, permission, acl, modTime)
                  : new INodeDirectoryAttributes.CopyWithQuota(
                      name,
                      permission,
                      acl,
                      modTime,
                      dirCopyInPb.getNsQuota(),
                      dirCopyInPb.getDsQuota());
        }
        // load created list
        List<INode> clist = loadCreatedList(in, dir, diffInPb.getCreatedListSize());
        // load deleted list
        List<INode> dlist =
            loadDeletedList(
                refList,
                in,
                dir,
                diffInPb.getDeletedINodeList(),
                diffInPb.getDeletedINodeRefList());
        // create the directory diff
        DirectoryDiff diff =
            new DirectoryDiff(snapshotId, copy, null, childrenSize, clist, dlist, useRoot);
        diffs.addFirst(diff);
      }
    }