@Override public INodeFile recordModification(final Snapshot latest, final INodeMap inodeMap) throws QuotaExceededException { if (isInLatestSnapshot(latest)) { INodeFileWithSnapshot newFile = getParent() .replaceChild4INodeFileWithSnapshot(this, inodeMap) .recordModification(latest, inodeMap); return newFile; } else { return this; } }
/** Replace a child {@link INodeFile} with an {@link INodeFileWithSnapshot}. */ INodeFileWithSnapshot replaceChild4INodeFileWithSnapshot( final INodeFile child, final INodeMap inodeMap) { Preconditions.checkArgument(!(child instanceof INodeFileWithSnapshot), "Child file is already an INodeFileWithSnapshot, child=" + child); final INodeFileWithSnapshot newChild = new INodeFileWithSnapshot(child); replaceChildFile(child, newChild, inodeMap); return newChild; }
/** * Test {@link INodeDirectory#getExistingPathINodes(byte[][], int, boolean)} * for snapshot file. */ @Test (timeout=15000) public void testSnapshotPathINodes() throws Exception { // Create a snapshot for the dir, and check the inodes for the path // pointing to a snapshot file hdfs.allowSnapshot(sub1); hdfs.createSnapshot(sub1, "s1"); // The path when accessing the snapshot file of file1 is // /TestSnapshot/sub1/.snapshot/s1/file1 String snapshotPath = sub1.toString() + "/.snapshot/s1/file1"; String[] names = INode.getPathNames(snapshotPath); byte[][] components = INode.getPathComponents(names); INodesInPath nodesInPath = INodesInPath.resolve(fsdir.rootDir, components); INode[] inodes = nodesInPath.getINodes(); // Length of inodes should be (components.length - 1), since we will ignore // ".snapshot" assertEquals(inodes.length, components.length - 1); // SnapshotRootIndex should be 3: {root, Testsnapshot, sub1, s1, file1} final Snapshot snapshot = getSnapshot(nodesInPath, "s1"); assertSnapshot(nodesInPath, true, snapshot, 3); // Check the INode for file1 (snapshot file) INode snapshotFileNode = inodes[inodes.length - 1]; assertINodeFile(snapshotFileNode, file1); assertTrue(snapshotFileNode.getParent() instanceof INodeDirectoryWithSnapshot); // Call getExistingPathINodes and request only one INode. nodesInPath = INodesInPath.resolve(fsdir.rootDir, components, 1, false); inodes = nodesInPath.getINodes(); assertEquals(inodes.length, 1); // The snapshotroot (s1) is not included in inodes. Thus the // snapshotRootIndex should be -1. assertSnapshot(nodesInPath, true, snapshot, -1); // Check the INode for file1 (snapshot file) assertINodeFile(nodesInPath.getLastINode(), file1); // Call getExistingPathINodes and request 2 INodes. nodesInPath = INodesInPath.resolve(fsdir.rootDir, components, 2, false); inodes = nodesInPath.getINodes(); assertEquals(inodes.length, 2); // There should be two INodes in inodes: s1 and snapshot of file1. Thus the // SnapshotRootIndex should be 0. assertSnapshot(nodesInPath, true, snapshot, 0); assertINodeFile(nodesInPath.getLastINode(), file1); // Resolve the path "/TestSnapshot/sub1/.snapshot" String dotSnapshotPath = sub1.toString() + "/.snapshot"; names = INode.getPathNames(dotSnapshotPath); components = INode.getPathComponents(names); nodesInPath = INodesInPath.resolve(fsdir.rootDir, components); inodes = nodesInPath.getINodes(); // The number of INodes returned should be components.length - 1 since we // will ignore ".snapshot" assertEquals(inodes.length, components.length - 1); // No SnapshotRoot dir is included in the resolved inodes assertSnapshot(nodesInPath, true, snapshot, -1); // The last INode should be the INode for sub1 final INode last = nodesInPath.getLastINode(); assertEquals(last.getFullPathName(), sub1.toString()); assertFalse(last instanceof INodeFileWithSnapshot); String[] invalidPathComponent = {"invalidDir", "foo", ".snapshot", "bar"}; Path invalidPath = new Path(invalidPathComponent[0]); for(int i = 1; i < invalidPathComponent.length; i++) { invalidPath = new Path(invalidPath, invalidPathComponent[i]); try { hdfs.getFileStatus(invalidPath); Assert.fail(); } catch(FileNotFoundException fnfe) { System.out.println("The exception is expected: " + fnfe); } } }
/** * Test {@link INodeDirectory#getExistingPathINodes(byte[][], int, boolean)} * for snapshot file while modifying file after snapshot. */ @Test (timeout=15000) public void testSnapshotPathINodesAfterModification() throws Exception { //file1 was deleted, create it again. DFSTestUtil.createFile(hdfs, file1, 1024, REPLICATION, seed); // First check the INode for /TestSnapshot/sub1/file1 String[] names = INode.getPathNames(file1.toString()); byte[][] components = INode.getPathComponents(names); INodesInPath nodesInPath = INodesInPath.resolve(fsdir.rootDir, components); INode[] inodes = nodesInPath.getINodes(); // The number of inodes should be equal to components.length assertEquals(inodes.length, components.length); assertSnapshot(nodesInPath, false, s4, -1); // The last INode should be associated with file1 assertEquals(inodes[components.length - 1].getFullPathName(), file1.toString()); // Create a snapshot for the dir, and check the inodes for the path // pointing to a snapshot file hdfs.allowSnapshot(sub1); hdfs.createSnapshot(sub1, "s3"); // Modify file1 DFSTestUtil.appendFile(hdfs, file1, "the content for appending"); // Check the INodes for snapshot of file1 String snapshotPath = sub1.toString() + "/.snapshot/s3/file1"; names = INode.getPathNames(snapshotPath); components = INode.getPathComponents(names); INodesInPath ssNodesInPath = INodesInPath.resolve(fsdir.rootDir, components); INode[] ssInodes = ssNodesInPath.getINodes(); // Length of ssInodes should be (components.length - 1), since we will // ignore ".snapshot" assertEquals(ssInodes.length, components.length - 1); final Snapshot s3 = getSnapshot(ssNodesInPath, "s3"); assertSnapshot(ssNodesInPath, true, s3, 3); // Check the INode for snapshot of file1 INode snapshotFileNode = ssInodes[ssInodes.length - 1]; assertEquals(snapshotFileNode.getLocalName(), file1.getName()); assertTrue(snapshotFileNode instanceof INodeFileWithSnapshot); // The modification time of the snapshot INode should be the same with the // original INode before modification assertEquals(inodes[inodes.length - 1].getModificationTime(), snapshotFileNode.getModificationTime(ssNodesInPath.getPathSnapshot())); // Check the INode for /TestSnapshot/sub1/file1 again names = INode.getPathNames(file1.toString()); components = INode.getPathComponents(names); INodesInPath newNodesInPath = INodesInPath.resolve(fsdir.rootDir, components); assertSnapshot(newNodesInPath, false, s3, -1); INode[] newInodes = newNodesInPath.getINodes(); // The number of inodes should be equal to components.length assertEquals(newInodes.length, components.length); // The last INode should be associated with file1 final int last = components.length - 1; assertEquals(newInodes[last].getFullPathName(), file1.toString()); // The modification time of the INode for file3 should have been changed Assert.assertFalse(inodes[last].getModificationTime() == newInodes[last].getModificationTime()); }