@Test public void testNoExceptionFromDirectoryWithRacyChildren() throws Exception { Stoppable stop = new StoppableImplementation(); HBaseTestingUtility localUtil = new HBaseTestingUtility(); Configuration conf = localUtil.getConfiguration(); final Path testDir = UTIL.getDataTestDir(); final FileSystem fs = UTIL.getTestFileSystem(); LOG.debug("Writing test data to: " + testDir); String confKey = "hbase.test.cleaner.delegates"; conf.set(confKey, AlwaysDelete.class.getName()); AllValidPaths chore = new AllValidPaths("test-file-cleaner", stop, conf, fs, testDir, confKey); AlwaysDelete delegate = (AlwaysDelete) chore.cleanersChain.get(0); AlwaysDelete spy = Mockito.spy(delegate); chore.cleanersChain.set(0, spy); final Path parent = new Path(testDir, "parent"); Path file = new Path(parent, "someFile"); fs.mkdirs(parent); fs.create(file).close(); assertTrue("Test file didn't get created.", fs.exists(file)); final Path racyFile = new Path(parent, "addedFile"); Mockito.doAnswer(new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { fs.create(racyFile).close(); FSUtils.logFileSystemState(fs, testDir, LOG); return (Boolean) invocation.callRealMethod(); } }).when(spy).isFileDeletable(Mockito.any(FileStatus.class)); if (chore.checkAndDeleteDirectory(parent)) { throw new Exception( "Reported success deleting directory, should have failed when adding file mid-iteration"); } assertTrue("Added file unexpectedly deleted", fs.exists(racyFile)); assertTrue("Parent directory deleted unexpectedly", fs.exists(parent)); assertFalse("Original file unexpectedly retained", fs.exists(file)); Mockito.verify(spy, Mockito.times(1)).isFileDeletable(Mockito.any(FileStatus.class)); }
@VisibleForTesting boolean checkAndDeleteDirectory(Path dir) { if (LOG.isTraceEnabled()) { LOG.trace("Checking directory: " + dir); } try { FileStatus[] children = FSUtils.listStatus(fs, dir); boolean allChildrenDeleted = checkAndDeleteEntries(children); if (!allChildrenDeleted) return false; } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); LOG.warn("Error while listing directory: " + dir, e); return false; } try { return fs.delete(dir, false); } catch (IOException e) { if (LOG.isTraceEnabled()) { LOG.trace("Couldn't delete directory: " + dir, e); } return false; } }
CleanerChore extends Chore { @VisibleForTesting boolean checkAndDeleteDirectory(Path dir) { if (LOG.isTraceEnabled()) { LOG.trace("Checking directory: " + dir); } try { FileStatus[] children = FSUtils.listStatus(fs, dir); boolean allChildrenDeleted = checkAndDeleteEntries(children); if (!allChildrenDeleted) return false; } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); LOG.warn("Error while listing directory: " + dir, e); return false; } try { return fs.delete(dir, false); } catch (IOException e) { if (LOG.isTraceEnabled()) { LOG.trace("Couldn't delete directory: " + dir, e); } return false; } } }
CleanerChore extends Chore { @VisibleForTesting boolean checkAndDeleteDirectory(Path dir) { if (LOG.isTraceEnabled()) { LOG.trace("Checking directory: " + dir); } try { FileStatus[] children = FSUtils.listStatus(fs, dir); boolean allChildrenDeleted = checkAndDeleteEntries(children); if (!allChildrenDeleted) return false; } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); LOG.warn("Error while listing directory: " + dir, e); return false; } try { return fs.delete(dir, false); } catch (IOException e) { if (LOG.isTraceEnabled()) { LOG.trace("Couldn't delete directory: " + dir, e); } return false; } } CleanerChore(String name, final int sleepPeriod, final Stoppable s, Configuration conf,
      FileSystem fs, Path oldFileDir, String confKey); }
CleanerChore extends Chore { @VisibleForTesting boolean checkAndDeleteDirectory(Path dir) { if (LOG.isTraceEnabled()) { LOG.trace("Checking directory: " + dir); } try { FileStatus[] children = FSUtils.listStatus(fs, dir); boolean allChildrenDeleted = checkAndDeleteEntries(children); if (!allChildrenDeleted) return false; } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); LOG.warn("Error while listing directory: " + dir, e); return false; } try { return fs.delete(dir, false); } catch (IOException e) { if (LOG.isTraceEnabled()) { LOG.trace("Couldn't delete directory: " + dir, e); } return false; } } CleanerChore(String name, final int sleepPeriod, final Stoppable s, Configuration conf,
      FileSystem fs, Path oldFileDir, String confKey); @Override void cleanup(); }
CleanerChore extends Chore { @VisibleForTesting boolean checkAndDeleteDirectory(Path dir) { if (LOG.isTraceEnabled()) { LOG.trace("Checking directory: " + dir); } try { FileStatus[] children = FSUtils.listStatus(fs, dir); boolean allChildrenDeleted = checkAndDeleteEntries(children); if (!allChildrenDeleted) return false; } catch (IOException e) { e = RemoteExceptionHandler.checkIOException(e); LOG.warn("Error while listing directory: " + dir, e); return false; } try { return fs.delete(dir, false); } catch (IOException e) { if (LOG.isTraceEnabled()) { LOG.trace("Couldn't delete directory: " + dir, e); } return false; } } CleanerChore(String name, final int sleepPeriod, final Stoppable s, Configuration conf,
      FileSystem fs, Path oldFileDir, String confKey); @Override void cleanup();  }