### Question:
CachedFlamdexReader implements FlamdexReader, MetricCache { @Override public void close() { try { if (readLockRef == null) { Closeables2.closeAll(log, metricCache, wrapped); } else { Closeables2.closeAll(log, metricCache, wrapped, readLockRef); } } finally { if (memory == null) { return; } if (memory.usedMemory() > 0) { log.error("CachedFlamdexReader is leaking! memory reserved after all memory has been freed: "+memory.usedMemory()); } Closeables2.closeQuietly(memory, log); } } CachedFlamdexReader(final MemoryReservationContext memory,
                                  final FlamdexReader wrapped,
                                  final @Nullable Closeable readLockRef,
                                  final @Nullable String indexName,
                                  final @Nullable String shardName,
                                  final @Nullable ImhotepMemoryCache<MetricKey, IntValueLookup> freeCache); @Override Collection<String> getIntFields(); @Override Collection<String> getStringFields(); @Override int getNumDocs(); @Override String getDirectory(); @Override DocIdStream getDocIdStream(); @Override IntTermIterator getIntTermIterator(String field); @Override StringTermIterator getStringTermIterator(String field); @Override IntTermDocIterator getIntTermDocIterator(final String field); @Override StringTermDocIterator getStringTermDocIterator(final String field); @Override long getIntTotalDocFreq(String field); @Override long getStringTotalDocFreq(String field); @Override Collection<String> getAvailableMetrics(); @Override IntValueLookup getMetric(String metric); StringValueLookup getStringLookup(final String field); @Override List<ImhotepStatusDump.MetricDump> getMetricDump(); @Override Set<String> getLoadedMetrics(); @Override long memoryRequired(String metric); @Override void close();  }### Answer:
@Test public void testClosing() throws FlamdexOutOfMemoryException, IOException { final ImhotepMemoryCache<MetricKey, IntValueLookup> cache = new ImhotepMemoryCache<MetricKey, IntValueLookup>(); final AtomicBoolean closed = new AtomicBoolean(false); FlamdexReader r = new SillyFlamdexReader() { @Override public void close() throws IOException { closed.set(true); } }; final MemoryReserver memory = new CachedMemoryReserver(new ImhotepMemoryPool(Long.MAX_VALUE), cache); final AtomicSharedReference<CachedFlamdexReader> resource = AtomicSharedReference.create(new CachedFlamdexReader(new MemoryReservationContext(memory), r, null, "test", "test", cache)); assertFalse(closed.get()); CachedFlamdexReaderReference cfr2 = new CachedFlamdexReaderReference(resource.get()); assertFalse(closed.get()); cfr2.close(); assertFalse(closed.get()); for (int i = 2; i < 10; ++i) { List<CachedFlamdexReaderReference> l = Lists.newArrayList(); for (int j = 0; j < i; ++j) { l.add(new CachedFlamdexReaderReference(resource.get())); assertFalse(closed.get()); } for (CachedFlamdexReaderReference cfr : l) { cfr.close(); assertFalse(closed.get()); } } final CachedFlamdexReaderReference cfr3 = new CachedFlamdexReaderReference(resource.get()); assertFalse(closed.get()); resource.unset(); assertFalse(closed.get()); cfr3.close(); assertTrue(closed.get()); closed.set(false); r = new SillyFlamdexReader() { @Override public void close() throws IOException { closed.set(true); } }; resource.set(new CachedFlamdexReader(new MemoryReservationContext(memory), r, null, "test", "test", cache)); cfr2 = new CachedFlamdexReaderReference(resource.get()); assertFalse(closed.get()); cfr2.close(); assertFalse(closed.get()); resource.set(null); assertTrue(closed.get()); }