/** * When destroying a reference node (WithName or DstReference), we call this * method to identify the snapshot which is the latest snapshot before the * reference node's creation. */ static int getPriorSnapshot(INodeReference ref) { WithCount wc = (WithCount) ref.getReferredINode(); WithName wn = null; if (ref instanceof DstReference) { wn = wc.getLastWithName(); } else if (ref instanceof WithName) { wn = wc.getPriorWithName((WithName) ref); } if (wn != null) { INode referred = wc.getReferredINode(); if (referred.isFile() && referred.asFile().isWithSnapshot()) { return referred.asFile().getDiffs().getPrior(wn.lastSnapshotId); } else if (referred.isDirectory()) { DirectoryWithSnapshotFeature sf = referred.asDirectory() .getDirectoryWithSnapshotFeature(); if (sf != null) { return sf.getDiffs().getPrior(wn.lastSnapshotId); } } } return Snapshot.NO_SNAPSHOT_ID; }
private int getSelfSnapshot(final int prior) { WithCount wc = (WithCount) getReferredINode().asReference(); INode referred = wc.getReferredINode(); int lastSnapshot = Snapshot.CURRENT_STATE_ID; if (referred.isFile() && referred.asFile().isWithSnapshot()) { lastSnapshot = referred.asFile().getDiffs().getLastSnapshotId(); } else if (referred.isDirectory()) { DirectoryWithSnapshotFeature sf = referred.asDirectory() .getDirectoryWithSnapshotFeature(); if (sf != null) { lastSnapshot = sf.getLastSnapshotId(); } } if (lastSnapshot != Snapshot.CURRENT_STATE_ID && lastSnapshot != prior) { return lastSnapshot; } else { return Snapshot.CURRENT_STATE_ID; } }
/** * Add a child inode to the directory. * * @param node INode to insert * @param setModTime set modification time for the parent node * not needed when replaying the addition and * the parent already has the proper mod time * @return false if the child with this name already exists; * otherwise, return true; */ public boolean addChild(INode node, final boolean setModTime, final int latestSnapshotId) throws QuotaExceededException { final int low = searchChildren(node.getLocalNameBytes()); if (low >= 0) { return false; } if (isInLatestSnapshot(latestSnapshotId)) { // create snapshot feature if necessary DirectoryWithSnapshotFeature sf = this.getDirectoryWithSnapshotFeature(); if (sf == null) { sf = this.addSnapshotFeature(null); } return sf.addChild(this, node, setModTime, latestSnapshotId); } addChild(node, low); if (setModTime) { // update modification time of the parent directory updateModificationTime(node.getModificationTime(), latestSnapshotId); } return true; }
/** * Undo the rename operation for the dst tree, i.e., if the rename operation * (with OVERWRITE option) removes a file/dir from the dst tree, add it back * and delete possible record in the deleted list. */ public void undoRename4DstParent(final BlockStoragePolicySuite bsps, final INode deletedChild, int latestSnapshotId) throws QuotaExceededException { DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); Preconditions.checkState(sf != null, "Directory does not have snapshot feature"); boolean removeDeletedChild = sf.getDiffs().removeChild(ListType.DELETED, deletedChild); int sid = removeDeletedChild ? Snapshot.CURRENT_STATE_ID : latestSnapshotId; final boolean added = addChild(deletedChild, true, sid); // update quota usage if adding is successfully and the old child has not // been stored in deleted list before if (added && !removeDeletedChild) { final QuotaCounts counts = deletedChild.computeQuotaUsage(bsps); addSpaceConsumed(counts, false); } }
@Override public void destroyAndCollectBlocks(final BlockStoragePolicySuite bsps, final BlocksMapUpdateInfo collectedBlocks, final List<INode> removedINodes) { final DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf != null) { sf.clear(bsps, this, collectedBlocks, removedINodes); } for (INode child : getChildrenList(Snapshot.CURRENT_STATE_ID)) { child.destroyAndCollectBlocks(bsps, collectedBlocks, removedINodes); } if (getAclFeature() != null) { AclStorage.removeAclFeature(getAclFeature()); } clear(); removedINodes.add(this); }
@Override public ContentSummaryComputationContext computeContentSummary(int snapshotId, ContentSummaryComputationContext summary) { final DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf != null && snapshotId == Snapshot.CURRENT_STATE_ID) { // if the getContentSummary call is against a non-snapshot path, the // computation should include all the deleted files/directories sf.computeContentSummary4Snapshot(summary.getBlockStoragePolicySuite(), summary.getCounts()); } final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature(); if (q != null && snapshotId == Snapshot.CURRENT_STATE_ID) { return q.computeContentSummary(this, summary); } else { return computeDirectoryContentSummary(summary, snapshotId); } }
@Override public void destroyAndCollectBlocks(ReclaimContext reclaimContext) { reclaimContext.quotaDelta().add( new QuotaCounts.Builder().nameSpace(1).build()); final DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf != null) { sf.clear(reclaimContext, this); } for (INode child : getChildrenList(Snapshot.CURRENT_STATE_ID)) { child.destroyAndCollectBlocks(reclaimContext); } if (getAclFeature() != null) { AclStorage.removeAclFeature(getAclFeature()); } clear(); reclaimContext.removedINodes.add(this); }
/** * Undo the rename operation for the dst tree, i.e., if the rename operation * (with OVERWRITE option) removes a file/dir from the dst tree, add it back * and delete possible record in the deleted list. */ public void undoRename4DstParent(final INode deletedChild, int latestSnapshotId) throws QuotaExceededException { DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); Preconditions.checkState(sf != null, "Directory does not have snapshot feature"); boolean removeDeletedChild = sf.getDiffs().removeChild(ListType.DELETED, deletedChild); int sid = removeDeletedChild ? Snapshot.CURRENT_STATE_ID : latestSnapshotId; final boolean added = addChild(deletedChild, true, sid); // update quota usage if adding is successfully and the old child has not // been stored in deleted list before if (added && !removeDeletedChild) { final Quota.Counts counts = deletedChild.computeQuotaUsage(); addSpaceConsumed(counts.get(Quota.NAMESPACE), counts.get(Quota.DISKSPACE), false); } }
private int getSelfSnapshot() { INode referred = getReferredINode().asReference().getReferredINode(); int snapshot = Snapshot.NO_SNAPSHOT_ID; if (referred.isFile() && referred.asFile().isWithSnapshot()) { snapshot = referred.asFile().getDiffs().getPrior(lastSnapshotId); } else if (referred.isDirectory()) { DirectoryWithSnapshotFeature sf = referred.asDirectory() .getDirectoryWithSnapshotFeature(); if (sf != null) { snapshot = sf.getDiffs().getPrior(lastSnapshotId); } } return snapshot; }
public DirectoryWithSnapshotFeature addSnapshotFeature( DirectoryDiffList diffs) { Preconditions.checkState(!isWithSnapshot(), "Directory is already with snapshot"); DirectoryWithSnapshotFeature sf = new DirectoryWithSnapshotFeature(diffs); addFeature(sf); return sf; }
/** add DirectorySnapshottableFeature */ public void addSnapshottableFeature() { Preconditions.checkState(!isSnapshottable(), "this is already snapshottable, this=%s", this); DirectoryWithSnapshotFeature s = this.getDirectoryWithSnapshotFeature(); final DirectorySnapshottableFeature snapshottable = new DirectorySnapshottableFeature(s); if (s != null) { this.removeFeature(s); } this.addFeature(snapshottable); }
/** remove DirectorySnapshottableFeature */ public void removeSnapshottableFeature() { DirectorySnapshottableFeature s = getDirectorySnapshottableFeature(); Preconditions.checkState(s != null, "The dir does not have snapshottable feature: this=%s", this); this.removeFeature(s); if (s.getDiffs().asList().size() > 0) { // add a DirectoryWithSnapshotFeature back DirectoryWithSnapshotFeature sf = new DirectoryWithSnapshotFeature( s.getDiffs()); addFeature(sf); } }
/** * Replace the given child with a new child. Note that we no longer need to * replace an normal INodeDirectory or INodeFile into an * INodeDirectoryWithSnapshot or INodeFileUnderConstruction. The only cases * for child replacement is for reference nodes. */ public void replaceChild(INode oldChild, final INode newChild, final INodeMap inodeMap) { Preconditions.checkNotNull(children); final int i = searchChildren(newChild.getLocalNameBytes()); Preconditions.checkState(i >= 0); Preconditions.checkState(oldChild == children.get(i) || oldChild == children.get(i).asReference().getReferredINode() .asReference().getReferredINode()); oldChild = children.get(i); if (oldChild.isReference() && newChild.isReference()) { // both are reference nodes, e.g., DstReference -> WithName final INodeReference.WithCount withCount = (WithCount) oldChild.asReference().getReferredINode(); withCount.removeReference(oldChild.asReference()); } children.set(i, newChild); // replace the instance in the created list of the diff list DirectoryWithSnapshotFeature sf = this.getDirectoryWithSnapshotFeature(); if (sf != null) { sf.getDiffs().replaceChild(ListType.CREATED, oldChild, newChild); } // update the inodeMap if (inodeMap != null) { inodeMap.put(newChild); } }
@Override public void recordModification(int latestSnapshotId) { if (isInLatestSnapshot(latestSnapshotId) && !shouldRecordInSrcSnapshot(latestSnapshotId)) { // add snapshot feature if necessary DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf == null) { sf = addSnapshotFeature(null); } // record self in the diff list if necessary sf.getDiffs().saveSelf2Snapshot(latestSnapshotId, this, null); } }
/** * Save the child to the latest snapshot. * * @return the child inode, which may be replaced. */ public INode saveChild2Snapshot(final INode child, final int latestSnapshotId, final INode snapshotCopy) { if (latestSnapshotId == Snapshot.CURRENT_STATE_ID) { return child; } // add snapshot feature if necessary DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf == null) { sf = this.addSnapshotFeature(null); } return sf.saveChild2Snapshot(this, child, latestSnapshotId, snapshotCopy); }
/** * @param name the name of the child * @param snapshotId * if it is not {@link Snapshot#CURRENT_STATE_ID}, get the result * from the corresponding snapshot; otherwise, get the result from * the current directory. * @return the child inode. */ public INode getChild(byte[] name, int snapshotId) { DirectoryWithSnapshotFeature sf; if (snapshotId == Snapshot.CURRENT_STATE_ID || (sf = getDirectoryWithSnapshotFeature()) == null) { ReadOnlyList<INode> c = getCurrentChildrenList(); final int i = ReadOnlyList.Util.binarySearch(c, name); return i < 0 ? null : c.get(i); } return sf.getChild(this, name, snapshotId); }
/** * Remove the specified child from this directory. */ public boolean removeChild(INode child, int latestSnapshotId) { if (isInLatestSnapshot(latestSnapshotId)) { // create snapshot feature if necessary DirectoryWithSnapshotFeature sf = this.getDirectoryWithSnapshotFeature(); if (sf == null) { sf = this.addSnapshotFeature(null); } return sf.removeChild(this, child, latestSnapshotId); } return removeChild(child); }
@Override public QuotaCounts computeQuotaUsage(BlockStoragePolicySuite bsps, byte blockStoragePolicyId, QuotaCounts counts, boolean useCache, int lastSnapshotId) { final DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); // we are computing the quota usage for a specific snapshot here, i.e., the // computation only includes files/directories that exist at the time of the // given snapshot if (sf != null && lastSnapshotId != Snapshot.CURRENT_STATE_ID && !(useCache && isQuotaSet())) { ReadOnlyList<INode> childrenList = getChildrenList(lastSnapshotId); for (INode child : childrenList) { final byte childPolicyId = child.getStoragePolicyIDForQuota(blockStoragePolicyId); child.computeQuotaUsage(bsps, childPolicyId, counts, useCache, lastSnapshotId); } counts.addNameSpace(1); return counts; } // compute the quota usage in the scope of the current directory tree final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature(); if (useCache && q != null && q.isQuotaSet()) { // use the cached quota return q.AddCurrentSpaceUsage(counts); } else { useCache = q != null && !q.isQuotaSet() ? false : useCache; return computeDirectoryQuotaUsage(bsps, blockStoragePolicyId, counts, useCache, lastSnapshotId); } }
/** Add quota usage for this inode excluding children. */ public QuotaCounts computeQuotaUsage4CurrentDirectory( BlockStoragePolicySuite bsps, byte storagePolicyId, QuotaCounts counts) { counts.addNameSpace(1); // include the diff list DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf != null) { sf.computeQuotaUsage4CurrentDirectory(bsps, storagePolicyId, counts); } return counts; }
@Override public ContentSummaryComputationContext computeContentSummary( ContentSummaryComputationContext summary) { final DirectoryWithSnapshotFeature sf = getDirectoryWithSnapshotFeature(); if (sf != null) { sf.computeContentSummary4Snapshot(summary.getBlockStoragePolicySuite(), summary.getCounts()); } final DirectoryWithQuotaFeature q = getDirectoryWithQuotaFeature(); if (q != null) { return q.computeContentSummary(this, summary); } else { return computeDirectoryContentSummary(summary, Snapshot.CURRENT_STATE_ID); } }