@Override public void close() throws IOException { try { super.close(); } finally { synchronized (REAPER_THREAD_LOCK) { --GLOBAL_SAFETY_NET_REGISTRY_COUNT; if (0 == GLOBAL_SAFETY_NET_REGISTRY_COUNT) { REAPER_THREAD.interrupt(); REAPER_THREAD = null; } } } }
/** * Registers a {@link Closeable} with the registry. In case the registry is already closed, this method throws an * {@link IllegalStateException} and closes the passed {@link Closeable}. * * @param closeable Closeable tor register * @throws IOException exception when the registry was closed before */ public final void registerCloseable(C closeable) throws IOException { if (null == closeable) { return; } synchronized (getSynchronizationLock()) { if (!closed) { doRegister(closeable, closeableToRef); return; } } IOUtils.closeQuietly(closeable); throw new IOException("Cannot register Closeable, registry is already closed. Closing argument."); }
/** * Removes a {@link Closeable} from the registry. * * @param closeable instance to remove from the registry. * @return true if the closeable was previously registered and became unregistered through this call. */ public final boolean unregisterCloseable(C closeable) { if (null == closeable) { return false; } synchronized (getSynchronizationLock()) { return doUnRegister(closeable, closeableToRef); } }
public boolean isClosed() { synchronized (getSynchronizationLock()) { return closed; } }
@Test public void testClose() throws Exception { setup(Integer.MAX_VALUE); startThreads(); for (int i = 0; i < 5; ++i) { System.gc(); Thread.sleep(40); } closeableRegistry.close(); joinThreads(); assertEquals(0, unclosedCounter.get()); assertEquals(0, closeableRegistry.getNumberOfRegisteredCloseables()); final TestCloseable testCloseable = new TestCloseable(); try { registerCloseable(testCloseable); fail("Closed registry should not accept closeables!"); } catch (IOException expected) {} assertTrue(testCloseable.isClosed()); assertEquals(0, unclosedCounter.get()); assertEquals(0, closeableRegistry.getNumberOfRegisteredCloseables()); }
@Override protected void registerCloseable(final Closeable closeable) throws IOException { closeableRegistry.registerCloseable(closeable); }
/** * Adds a mapping to the registry map, respecting locking. */ protected final void addCloseableInternal(Closeable closeable, T metaData) { synchronized (getSynchronizationLock()) { closeableToRef.put(closeable, metaData); } }
@Test public void testNonBlockingClose() throws Exception { setup(Integer.MAX_VALUE); final BlockingTestCloseable blockingCloseable = new BlockingTestCloseable(); registerCloseable(blockingCloseable); assertEquals(1, closeableRegistry.getNumberOfRegisteredCloseables()); Thread closer = new Thread(() -> { try { closeableRegistry.close(); } catch (IOException ignore) { } }); closer.start(); blockingCloseable.awaitClose(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS); final TestCloseable testCloseable = new TestCloseable(); try { registerCloseable(testCloseable); fail("Closed registry should not accept closeables!"); } catch (IOException ignored) {} blockingCloseable.unblockClose(); closer.join(); assertTrue(testCloseable.isClosed()); assertEquals(0, closeableRegistry.getNumberOfRegisteredCloseables()); }
@Override protected void registerCloseable(final Closeable closeable) throws IOException { final WrappingProxyCloseable<Closeable> wrappingProxyCloseable = new WrappingProxyCloseable<Closeable>() { @Override public void close() throws IOException { closeable.close(); } @Override public Closeable getWrappedDelegate() { return closeable; } }; closeableRegistry.registerCloseable(wrappingProxyCloseable); }
/** * Removes a mapping from the registry map, respecting locking. */ protected final void removeCloseableInternal(Closeable closeable) { synchronized (getSynchronizationLock()) { closeableToRef.remove(closeable); } }
/** * Removes a {@link Closeable} from the registry. * * @param closeable instance to remove from the registry. * @return true if the closeable was previously registered and became unregistered through this call. */ public final boolean unregisterCloseable(C closeable) { if (null == closeable) { return false; } synchronized (getSynchronizationLock()) { return doUnRegister(closeable, closeableToRef); } }
/** * Registers a {@link Closeable} with the registry. In case the registry is already closed, this method throws an * {@link IllegalStateException} and closes the passed {@link Closeable}. * * @param closeable Closeable tor register * @throws IOException exception when the registry was closed before */ public final void registerCloseable(C closeable) throws IOException { if (null == closeable) { return; } synchronized (getSynchronizationLock()) { if (!closed) { doRegister(closeable, closeableToRef); return; } } IOUtils.closeQuietly(closeable); throw new IOException("Cannot register Closeable, registry is already closed. Closing argument."); }
@Test public void testSafetyNetClose() throws Exception { setup(20); startThreads(); joinThreads(); for (int i = 0; i < 5 && unclosedCounter.get() > 0; ++i) { System.gc(); Thread.sleep(50); } Assert.assertEquals(0, unclosedCounter.get()); closeableRegistry.close(); }
@Override protected void createAndRegisterStream() throws IOException { TestStream testStream = new TestStream(unclosedCounter); registry.registerCloseable(testStream); } };
@VisibleForTesting public final int getNumberOfRegisteredCloseables() { synchronized (getSynchronizationLock()) { return closeableToRef.size(); } }
/** * Removes a {@link Closeable} from the registry. * * @param closeable instance to remove from the registry. * @return true if the closeable was previously registered and became unregistered through this call. */ public final boolean unregisterCloseable(C closeable) { if (null == closeable) { return false; } synchronized (getSynchronizationLock()) { return doUnRegister(closeable, closeableToRef); } }
/** * Registers a {@link Closeable} with the registry. In case the registry is already closed, this method throws an * {@link IllegalStateException} and closes the passed {@link Closeable}. * * @param closeable Closeable tor register * @throws IOException exception when the registry was closed before */ public final void registerCloseable(C closeable) throws IOException { if (null == closeable) { return; } synchronized (getSynchronizationLock()) { if (!closed) { doRegister(closeable, closeableToRef); return; } } IOUtils.closeQuietly(closeable); throw new IOException("Cannot register Closeable, registry is already closed. Closing argument."); }
@Override public void close() throws IOException { try { super.close(); } finally { synchronized (REAPER_THREAD_LOCK) { --GLOBAL_SAFETY_NET_REGISTRY_COUNT; if (0 == GLOBAL_SAFETY_NET_REGISTRY_COUNT) { REAPER_THREAD.interrupt(); REAPER_THREAD = null; } } } }
@VisibleForTesting public final boolean isCloseableRegistered(Closeable c) { synchronized (getSynchronizationLock()) { return closeableToRef.containsKey(c); } } }
@Override public void close() throws IOException { try { super.close(); } finally { synchronized (REAPER_THREAD_LOCK) { --GLOBAL_SAFETY_NET_REGISTRY_COUNT; if (0 == GLOBAL_SAFETY_NET_REGISTRY_COUNT) { REAPER_THREAD.interrupt(); REAPER_THREAD = null; } } } }