Index: src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (revision 1790409) +++ src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (working copy) @@ -155,6 +155,21 @@ @Nonnull private final SegmentNotFoundExceptionListener snfeListener; + private final Supplier> referencesSupplier = new Supplier>() { + + @Override + public Set get() { + Set references = newHashSet(); + for (SegmentId id : tracker.getReferencedSegmentIds()) { + if (id.isBulkSegmentId()) { + references.add(id.asUUID()); + } + } + return references; + } + + }; + FileStore(final FileStoreBuilder builder) throws InvalidFileStoreVersionException, IOException { super(builder); @@ -810,13 +825,7 @@ // to clear stale weak references in the SegmentTracker System.gc(); - Set bulkRefs = newHashSet(); - for (SegmentId id : tracker.getReferencedSegmentIds()) { - if (id.isBulkSegmentId()) { - bulkRefs.add(id.asUUID()); - } - } - CleanupResult cleanupResult = tarFiles.cleanup(bulkRefs, compactionResult.reclaimer()); + CleanupResult cleanupResult = tarFiles.cleanup(referencesSupplier, compactionResult.reclaimer()); if (cleanupResult.isInterrupted()) { gcListener.info("TarMK GC #{}: cleanup interrupted", GC_COUNT); } Index: src/main/java/org/apache/jackrabbit/oak/segment/file/TarFiles.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/file/TarFiles.java (revision 1790409) +++ src/main/java/org/apache/jackrabbit/oak/segment/file/TarFiles.java (working copy) @@ -45,6 +45,7 @@ import java.util.regex.Pattern; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; import com.google.common.io.Closer; import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector; import org.apache.jackrabbit.oak.segment.SegmentGraph.SegmentGraphVisitor; @@ -404,7 +405,7 @@ writer = newWriter; } - CleanupResult cleanup(Set references, Predicate reclaimGeneration) throws IOException { + CleanupResult cleanup(Supplier> referencesSupplier, Predicate reclaimGeneration) throws IOException { checkReadWrite(); CleanupResult result = new CleanupResult(); @@ -437,6 +438,13 @@ cleaned.put(reader, reader); result.reclaimedSize += reader.size(); } + + // The set of references has to be computed while holding the lock. + // This prevents a time-of-check to time-of-use race condition. See + // OAK-6046 for further details. + + Set references = referencesSupplier.get(); + Set reclaim = newHashSet(); for (TarReader reader : cleaned.keySet()) { if (shutdown) {