Index: src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java (working copy) @@ -37,4 +37,9 @@ throw new IllegalStateException("invalid use"); } + @Override + public int size() { + throw new IllegalStateException("invalid use"); + } + } Index: src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java (working copy) @@ -85,7 +85,8 @@ * @return the number of references (segment IDs) accessible from this * instance. */ - int size() { + @Override + public int size() { synchronized (lock) { return numbers.size(); } Index: src/main/java/org/apache/jackrabbit/oak/segment/Segment.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (working copy) @@ -229,7 +229,7 @@ } int position = HEADER_SIZE + data.position() - + getReferencedSegmentIdCount() * SEGMENT_REFERENCE_SIZE; + + readReferencedSegmentIdCount() * SEGMENT_REFERENCE_SIZE; int maxIndex = data.getInt(position + (recordNumberCount - 1) * 9); byte[] types = new byte[maxIndex + 1]; @@ -250,10 +250,8 @@ private SegmentReferences readReferencedSegments( final SegmentIdProvider idProvider) { - checkState(getReferencedSegmentIdCount() + 1 < 0xffff, - "Segment cannot have more than 0xffff references"); - - final int referencedSegmentIdCount = getReferencedSegmentIdCount(); + final int referencedSegmentIdCount = readReferencedSegmentIdCount(); + checkState(referencedSegmentIdCount + 1 < 0xffff, "Segment cannot have more than 0xffff references"); final int refOffset = data.position() + HEADER_SIZE; final SegmentId[] refIds = new SegmentId[referencedSegmentIdCount]; return new SegmentReferences() { @@ -276,6 +274,11 @@ return id; } + @Override + public int size() { + return referencedSegmentIdCount; + } + @Nonnull @Override public Iterator iterator() { @@ -354,6 +357,10 @@ } public int getReferencedSegmentIdCount() { + return segmentReferences.size(); + } + + private int readReferencedSegmentIdCount() { return data.getInt(REFERENCED_SEGMENT_ID_COUNT_OFFSET); } Index: src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (working copy) @@ -38,7 +38,10 @@ import java.io.IOException; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; +import java.util.UUID; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -448,4 +451,16 @@ return new RecordId(segment.getSegmentId(), recordNumber); } + @Override + public Set getReferencedSegmentIds() { + if (segment == null) { + return Collections.emptySet(); + } + Set result = new HashSet<>(); + for (int i = 0; i < segment.getReferencedSegmentIdCount(); i++) { + result.add(segment.getReferencedSegmentId(i)); + } + return result; + } + } Index: src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java (working copy) @@ -27,9 +27,11 @@ import static java.lang.Thread.currentThread; import java.io.IOException; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import javax.annotation.Nonnull; @@ -240,4 +242,22 @@ return wid + "." + writerId; } } + + @Override + public Set getReferencedSegmentIds() { + Set result = new HashSet<>(); + poolMonitor.enter(); + try { + for (SegmentBufferWriter w : borrowed) { + result.addAll(w.getReferencedSegmentIds()); + } + for (SegmentBufferWriter w : disposed) { + result.addAll(w.getReferencedSegmentIds()); + } + } finally { + poolMonitor.leave(); + } + return result; + } + } Index: src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java (working copy) @@ -31,4 +31,11 @@ */ SegmentId getSegmentId(int reference); + /** + * Return the number of references in this instance. + * + * @return The numer of segment references in this instance. + */ + int size(); + } Index: src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java (working copy) @@ -55,6 +55,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.UUID; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -1147,4 +1149,8 @@ this.compactionMonitor = compactionMonitor; } + public Set getReferencedSegmentIds() { + return writeOperationHandler.getReferencedSegmentIds(); + } + } Index: src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriterBuilder.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriterBuilder.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriterBuilder.java (working copy) @@ -21,6 +21,9 @@ import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Set; +import java.util.UUID; + import javax.annotation.Nonnull; import com.google.common.base.Supplier; @@ -177,6 +180,12 @@ public void flush(@Nonnull SegmentStore store) { throw new UnsupportedOperationException("Cannot write to read-only store"); } + + @Override + public Set getReferencedSegmentIds() { + throw new UnsupportedOperationException("Cannot write to read-only store"); + } + }); } Index: src/main/java/org/apache/jackrabbit/oak/segment/WriteOperationHandler.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/WriteOperationHandler.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/WriteOperationHandler.java (working copy) @@ -20,6 +20,8 @@ package org.apache.jackrabbit.oak.segment; import java.io.IOException; +import java.util.Set; +import java.util.UUID; import javax.annotation.Nonnull; @@ -62,4 +64,14 @@ * @throws IOException */ void flush(@Nonnull SegmentStore store) throws IOException; + + /** + * Returns the identifiers of segments referenced by the data written by + * this instance. + * + * @return The identifiers of segments referenced by the data written by + * this instance. + */ + Set getReferencedSegmentIds(); + } Index: src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (revision 1790395) +++ src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (working copy) @@ -816,6 +816,11 @@ bulkRefs.add(id.asUUID()); } } + for (UUID id : segmentWriter.getReferencedSegmentIds()) { + if (!SegmentId.isDataSegmentId(id.getLeastSignificantBits())) { + bulkRefs.add(id); + } + } CleanupResult cleanupResult = tarFiles.cleanup(bulkRefs, compactionResult.reclaimer()); if (cleanupResult.isInterrupted()) { gcListener.info("TarMK GC #{}: cleanup interrupted", GC_COUNT);