@Override public boolean rename(final Path src, final Path dst) throws IOException { // passing resolveLastComponet as false to catch renaming a mount point to // itself. We need to catch this as an internal operation and fail. InodeTree.ResolveResult<FileSystem> resSrc = fsState.resolve(getUriPath(src), false); if (resSrc.isInternalDir()) { throw readOnlyMountTable("rename", src); } InodeTree.ResolveResult<FileSystem> resDst = fsState.resolve(getUriPath(dst), false); if (resDst.isInternalDir()) { throw readOnlyMountTable("rename", dst); } /** * // Alternate 1: renames within same file system - valid but we disallow // Alternate 2: (as * described in next para - valid but we have disallowed it // // Note we compare the URIs. the * URIs include the link targets. // hence we allow renames across mount links as long as the * mount links // point to the same target. if (!resSrc.targetFileSystem.getUri().equals( * resDst.targetFileSystem.getUri())) { throw new IOException("Renames across Mount points not * supported"); } */ // // Alternate 3 : renames ONLY within the the same mount links. // if (resSrc.targetFileSystem != resDst.targetFileSystem) { throw new IOException("Renames across Mount points not supported"); } return resSrc.targetFileSystem.rename(resSrc.remainingPath, resDst.remainingPath); }
@Test public void getInodeByNonexistingNestedPathTest() throws Exception { mThrown.expect(InvalidPathException.class); mThrown.expectMessage("Path /nested/test/file does not exist"); mTree.createPath(NESTED_URI, sNestedDirectoryOptions); mTree.getInodeByPath(NESTED_FILE_URI); }
@Test public void initializeRootTwiceTest() throws Exception { Inode root = mTree.getInodeByPath(new TachyonURI("/")); // initializeRoot call does nothing mTree.initializeRoot(TEST_PERMISSION_STATUS); Inode newRoot = mTree.getInodeByPath(new TachyonURI("/")); Assert.assertEquals(root, newRoot); }
@Test public void createFileUnderFileTest() throws Exception { mThrown.expect(InvalidPathException.class); mThrown.expectMessage( "Could not traverse to parent directory of path /nested/test/test." + " Component test is not a directory."); mTree.createPath(NESTED_URI, sNestedFileOptions); mTree.createPath(new TachyonURI("/nested/test/test"), sNestedFileOptions); }
@Test public void createFileTest() throws Exception { // created nested file mTree.createPath(NESTED_FILE_URI, sNestedFileOptions); Inode nestedFile = mTree.getInodeByPath(NESTED_FILE_URI); Assert.assertEquals("file", nestedFile.getName()); Assert.assertEquals(2, nestedFile.getParentId()); Assert.assertTrue(nestedFile.isFile()); Assert.assertEquals("user1", nestedFile.getUserName()); Assert.assertTrue(nestedFile.getGroupName().isEmpty()); Assert.assertEquals((short) 0644, nestedFile.getPermission()); }
@Test public void getInodeChildrenRecursiveTest() throws Exception { mTree.createPath(TEST_URI, sDirectoryOptions); mTree.createPath(NESTED_URI, sNestedDirectoryOptions); // add nested file mTree.createPath(NESTED_FILE_URI, sNestedFileOptions); // all inodes under root List<Inode> inodes = mTree.getInodeChildrenRecursive((InodeDirectory) mTree.getInodeById(0)); // /test, /nested, /nested/test, /nested/test/file Assert.assertEquals(4, inodes.size()); }
@Test public void createExistingDirectoryTest() throws Exception { // create directory mTree.createPath(TEST_URI, sDirectoryOptions); // create again with allowExists true mTree.createPath(TEST_URI, new CreatePathOptions.Builder().setAllowExists(true).build()); // create again with allowExists false mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage(ExceptionMessage.FILE_ALREADY_EXISTS.getMessage(TEST_URI)); mTree.createPath(TEST_URI, new CreatePathOptions.Builder().setAllowExists(false).build()); }
@Test public void createPathTest() throws Exception { // save the last mod time of the root long lastModTime = mTree.getRoot().getLastModificationTimeMs(); // sleep to ensure a different last modification time CommonUtils.sleepMs(10); // create nested directory InodeTree.CreatePathResult createResult = mTree.createPath(NESTED_URI, sNestedDirectoryOptions); List<Inode> modified = createResult.getModified(); List<Inode> created = createResult.getCreated(); // 1 modified directory Assert.assertEquals(1, modified.size()); Assert.assertEquals("", modified.get(0).getName()); Assert.assertNotEquals(lastModTime, modified.get(0).getLastModificationTimeMs()); // 2 created directories Assert.assertEquals(2, created.size()); Assert.assertEquals("nested", created.get(0).getName()); Assert.assertEquals("test", created.get(1).getName()); // save the last mod time of 'test' lastModTime = created.get(1).getLastModificationTimeMs(); // sleep to ensure a different last modification time CommonUtils.sleepMs(10); // creating the directory path again results in no new inodes. try { createResult = mTree.createPath(NESTED_URI, sNestedDirectoryOptions); Assert.assertTrue("createPath should throw FileAlreadyExistsException", false); } catch (FileAlreadyExistsException faee) { Assert.assertEquals( faee.getMessage(), ExceptionMessage.FILE_ALREADY_EXISTS.getMessage(NESTED_URI)); } // create a file CreatePathOptions options = new CreatePathOptions.Builder(MasterContext.getConf()) .setBlockSizeBytes(Constants.KB) .setRecursive(true) .build(); createResult = mTree.createPath(NESTED_FILE_URI, options); modified = createResult.getModified(); created = createResult.getCreated(); // test directory was modified Assert.assertEquals(1, modified.size()); Assert.assertEquals("test", modified.get(0).getName()); Assert.assertNotEquals(lastModTime, modified.get(0).getLastModificationTimeMs()); // file was created Assert.assertEquals(1, created.size()); Assert.assertEquals("file", created.get(0).getName()); }
@Test public void getInodeByNonexistingPathTest() throws Exception { mThrown.expect(InvalidPathException.class); mThrown.expectMessage("Path /test does not exist"); mTree.getInodeByPath(TEST_URI); }
@Test public void createFileUnderNonexistingDirTest() throws Exception { mThrown.expect(InvalidPathException.class); mThrown.expectMessage("File /nested/test creation failed. Component 1(nested) does not exist"); mTree.createPath(NESTED_URI, sFileOptions); }
@Test public void createRootPathTest() throws Exception { mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage("/"); mTree.createPath(new TachyonURI("/"), sFileOptions); }
@Test public void createFileUnderPinnedDirectoryTest() throws Exception { // create nested directory InodeTree.CreatePathResult createResult = mTree.createPath(NESTED_URI, sNestedDirectoryOptions); List<Inode> created = createResult.getCreated(); Inode nested = created.get(created.size() - 1); // pin nested folder mTree.setPinned(nested, true); // create nested file under pinned folder mTree.createPath(NESTED_FILE_URI, sNestedFileOptions); // the nested file is pinned Assert.assertEquals(1, mTree.getPinIdSet().size()); }
@Override public BlockLocation[] getFileBlockLocations(FileStatus fs, long start, long len) throws IOException { final InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(fs.getPath()), true); return res.targetFileSystem.getFileBlockLocations( new ViewFsFileStatus(fs, res.remainingPath), start, len); }
@Test public void getInodeByInvalidIdTest() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage("Inode id 1 does not exist"); mTree.getInodeById(1); }
@Override public void setWriteChecksum(final boolean writeChecksum) { List<InodeTree.MountPoint<FileSystem>> mountPoints = fsState.getMountPoints(); for (InodeTree.MountPoint<FileSystem> mount : mountPoints) { mount.target.targetFileSystem.setWriteChecksum(writeChecksum); } }
@Test public void createFileTwiceTest() throws Exception { mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage("/nested/test"); mTree.createPath(NESTED_URI, sNestedFileOptions); mTree.createPath(NESTED_URI, sNestedFileOptions); }
// verify that the tree has the given children private static void verifyChildrenNames( InodeTree tree, InodeDirectory root, Set<String> childNames) throws Exception { List<Inode> children = tree.getInodeChildrenRecursive(root); Assert.assertEquals(childNames.size(), children.size()); for (Inode child : children) { Assert.assertTrue(childNames.contains(child.getName())); } }
// helper for verifying that correct objects were journaled to the output stream private static void verifyJournal(InodeTree root, List<Inode> journaled) throws Exception { JournalOutputStream mockOutputStream = Mockito.mock(JournalOutputStream.class); root.streamToJournalCheckpoint(mockOutputStream); for (Inode node : journaled) { Mockito.verify(mockOutputStream).writeEntry(node.toJournalEntry()); } Mockito.verifyNoMoreInteractions(mockOutputStream); }
@Test public void createFileWithNegativeBlockSizeTest() throws Exception { mThrown.expect(BlockInfoException.class); mThrown.expectMessage("Invalid block size -1"); CreatePathOptions options = new CreatePathOptions.Builder(MasterContext.getConf()).setBlockSizeBytes(-1).build(); mTree.createPath(TEST_URI, options); }
@Override public short getDefaultReplication(Path f) { try { InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(f), true); return res.targetFileSystem.getDefaultReplication(res.remainingPath); } catch (FileNotFoundException e) { throw new NotInMountpointException(f, "getDefaultReplication"); } }
@Override public Path resolvePath(final Path f) throws IOException { final InodeTree.ResolveResult<FileSystem> res; res = fsState.resolve(getUriPath(f), true); if (res.isInternalDir()) { return f; } return res.targetFileSystem.resolvePath(res.remainingPath); }
@Override public boolean delete(final Path f, final boolean recursive) throws AccessControlException, FileNotFoundException, IOException { InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(f), true); // If internal dir or target is a mount link (ie remainingPath is Slash) if (res.isInternalDir() || res.remainingPath == InodeTree.SlashPath) { throw readOnlyMountTable("delete", f); } return res.targetFileSystem.delete(res.remainingPath, recursive); }
@Override public FileSystem[] getChildFileSystems() { List<InodeTree.MountPoint<FileSystem>> mountPoints = fsState.getMountPoints(); Set<FileSystem> children = new HashSet<FileSystem>(); for (InodeTree.MountPoint<FileSystem> mountPoint : mountPoints) { FileSystem targetFs = mountPoint.target.targetFileSystem; children.addAll(Arrays.asList(targetFs.getChildFileSystems())); } return children.toArray(new FileSystem[] {}); }
@Test public void streamToJournalCheckpointTest() throws Exception { InodeDirectory root = mTree.getRoot(); // test root verifyJournal(mTree, Lists.<Inode>newArrayList(root)); // test nested URI mTree.createPath(NESTED_FILE_URI, sNestedFileOptions); InodeDirectory nested = (InodeDirectory) root.getChild("nested"); InodeDirectory test = (InodeDirectory) nested.getChild("test"); Inode file = test.getChild("file"); verifyJournal(mTree, Lists.newArrayList(root, nested, test, file)); // add a sibling of test and verify journaling is in correct order (breadth first) mTree.createPath(new TachyonURI("/nested/test1/file1"), sNestedFileOptions); InodeDirectory test1 = (InodeDirectory) nested.getChild("test1"); Inode file1 = test1.getChild("file1"); verifyJournal(mTree, Lists.newArrayList(root, nested, test, test1, file, file1)); }
public MountPoint[] getMountPoints() { List<InodeTree.MountPoint<FileSystem>> mountPoints = fsState.getMountPoints(); MountPoint[] result = new MountPoint[mountPoints.size()]; for (int i = 0; i < mountPoints.size(); ++i) { result[i] = new MountPoint( new Path(mountPoints.get(i).src), mountPoints.get(i).target.targetDirLinkList); } return result; }
@Before public void before() throws Exception { Journal blockJournal = new ReadWriteJournal(mTestFolder.newFolder().getAbsolutePath()); BlockMaster blockMaster = new BlockMaster(blockJournal); InodeDirectoryIdGenerator directoryIdGenerator = new InodeDirectoryIdGenerator(blockMaster); MountTable mountTable = new MountTable(); mTree = new InodeTree(blockMaster, directoryIdGenerator, mountTable); blockMaster.start(true); mTree.initializeRoot(TEST_PERMISSION_STATUS); }
@Test public void createDirectoryTest() throws Exception { // create directory mTree.createPath(TEST_URI, sDirectoryOptions); Inode test = mTree.getInodeByPath(TEST_URI); Assert.assertEquals(TEST_PATH, test.getName()); Assert.assertTrue(test.isDirectory()); Assert.assertEquals("user1", test.getUserName()); Assert.assertTrue(test.getGroupName().isEmpty()); Assert.assertEquals((short) 0755, test.getPermission()); // create nested directory mTree.createPath(NESTED_URI, sNestedDirectoryOptions); Inode nested = mTree.getInodeByPath(NESTED_URI); Assert.assertEquals(TEST_PATH, nested.getName()); Assert.assertEquals(2, nested.getParentId()); Assert.assertTrue(test.isDirectory()); Assert.assertEquals("user1", test.getUserName()); Assert.assertTrue(test.getGroupName().isEmpty()); Assert.assertEquals((short) 0755, test.getPermission()); }
@Test public void deleteNonexistingInodeTest() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage("Inode id 1 does not exist"); Inode testFile = new InodeFile.Builder() .setName("testFile1") .setId(1) .setParentId(1) .setPermissionStatus(TEST_PERMISSION_STATUS) .build(); mTree.deleteInode(testFile); }
@Override public Path getHomeDirectory() { if (homeDir == null) { String base = fsState.getHomeDirPrefixValue(); if (base == null) { base = "/user"; } homeDir = (base.equals("/") ? this.makeQualified(new Path(base + ugi.getShortUserName())) : this.makeQualified(new Path(base + "/" + ugi.getShortUserName()))); } return homeDir; }
@Override public FileStatus getFileStatus(final Path f) throws AccessControlException, FileNotFoundException, IOException { InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(f), true); // FileStatus#getPath is a fully qualified path relative to the root of // target file system. // We need to change it to viewfs URI - relative to root of mount table. // The implementors of RawLocalFileSystem were trying to be very smart. // They implement FileStatus#getOwener lazily -- the object // returned is really a RawLocalFileSystem that expect the // FileStatus#getPath to be unchanged so that it can get owner when needed. // Hence we need to interpose a new ViewFileSystemFileStatus that // works around. FileStatus status = res.targetFileSystem.getFileStatus(res.remainingPath); return new ViewFsFileStatus(status, this.makeQualified(f)); }