Index: oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/SegmentTarExplorerBackend.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/SegmentTarExplorerBackend.java (revision 1746972) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/explorer/SegmentTarExplorerBackend.java (working copy) @@ -174,7 +174,7 @@ @Override public NodeState readNodeState(String recordId) { - return store.getReader().readNode(RecordId.fromString(store.getTracker(), recordId)); + return store.getReader().readNode(RecordId.fromString(store, recordId)); } @Override Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java (revision 1746972) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java (working copy) @@ -308,12 +308,12 @@ if (tokens[0].equalsIgnoreCase("head")) { idL = store.getRevisions().getHead(); } else { - idL = fromString(store.getTracker(), tokens[0]); + idL = fromString(store, tokens[0]); } if (tokens[1].equalsIgnoreCase("head")) { idR = store.getRevisions().getHead(); } else { - idR = fromString(store.getTracker(), tokens[1]); + idR = fromString(store, tokens[1]); } } catch (IllegalArgumentException ex) { System.out.println("Error parsing revision interval '" + interval + "': " + ex.getMessage()); @@ -344,9 +344,9 @@ return; } Iterator revDiffsIt = revDiffs.iterator(); - RecordId idLt = fromString(store.getTracker(), revDiffsIt.next()); + RecordId idLt = fromString(store, revDiffsIt.next()); while (revDiffsIt.hasNext()) { - RecordId idRt = fromString(store.getTracker(), revDiffsIt.next()); + RecordId idRt = fromString(store, revDiffsIt.next()); boolean good = diff(store, idLt, idRt, filter, pw); idLt = idRt; if (!good && !ignoreSNFEs) { @@ -585,7 +585,7 @@ System.err.println("Unknown argument: " + args[i]); } else if (matcher.group(1) != null) { UUID uuid = UUID.fromString(matcher.group(1)); - SegmentId id = store.getTracker().getSegmentId( + SegmentId id = store.getSegmentId( uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); System.out.println(id.getSegment()); @@ -593,10 +593,10 @@ RecordId id1 = store.getRevisions().getHead(); RecordId id2 = null; if (matcher.group(2) != null) { - id1 = fromString(store.getTracker(), + id1 = fromString(store, matcher.group(3)); if (matcher.group(4) != null) { - id2 = fromString(store.getTracker(), + id2 = fromString(store, matcher.group(5)); } } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java (working copy) @@ -42,7 +42,7 @@ public static RecordId[] EMPTY_ARRAY = new RecordId[0]; - public static RecordId fromString(SegmentTracker factory, String id) { + public static RecordId fromString(SegmentStore factory, String id) { Matcher matcher = PATTERN.matcher(id); if (matcher.matches()) { UUID uuid = UUID.fromString(matcher.group(1)); Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (working copy) @@ -125,7 +125,7 @@ public static final int GC_GENERATION_OFFSET = 10; @Nonnull - private final SegmentTracker tracker; + private final SegmentStore store; @Nonnull private final SegmentReader reader; @@ -189,11 +189,11 @@ return (address + boundary - 1) & ~(boundary - 1); } - public Segment(@Nonnull SegmentTracker tracker, + public Segment(@Nonnull SegmentStore store, @Nonnull SegmentReader reader, @Nonnull final SegmentId id, @Nonnull final ByteBuffer data) { - this.tracker = checkNotNull(tracker); + this.store = checkNotNull(store); this.reader = checkNotNull(reader); this.id = checkNotNull(id); @@ -237,13 +237,13 @@ } } - Segment(@Nonnull SegmentTracker tracker, + Segment(@Nonnull SegmentStore store, @Nonnull SegmentReader reader, @Nonnull byte[] buffer, @Nonnull String info) { - this.tracker = checkNotNull(tracker); + this.store = checkNotNull(store); this.reader = checkNotNull(reader); - this.id = tracker.newDataSegmentId(); + this.id = store.newDataSegmentId(); this.info = checkNotNull(info); if (DISABLE_TEMPLATE_CACHE) { templates = null; @@ -370,7 +370,7 @@ int refpos = data.position() + index * 16; long msb = data.getLong(refpos); long lsb = data.getLong(refpos + 8); - refid = tracker.getSegmentId(msb, lsb); + refid = store.getSegmentId(msb, lsb); refids[index] = refid; } } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (working copy) @@ -187,7 +187,7 @@ ",\"sno\":" + tracker.getSegmentCount() + ",\"t\":" + currentTimeMillis() + "}"; try { - segment = new Segment(tracker, reader, buffer, metaInfo); + segment = new Segment(store, reader, buffer, metaInfo); byte[] data = metaInfo.getBytes(UTF_8); RecordWriters.newValueWriter(data.length, data).write(this); } catch (IOException e) { Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java (working copy) @@ -163,13 +163,13 @@ SegmentNodeState root = checkNotNull(fileStore).getReader().readHeadState(); Predicate filter = pattern == null ? Predicates.alwaysTrue() - : createRegExpFilter(pattern, fileStore.getTracker()); + : createRegExpFilter(pattern, fileStore); Graph segmentGraph = parseSegmentGraph(fileStore, filter); Graph headGraph = parseHeadGraph(fileStore.getReader(), root.getRecordId()); writer.write("nodedef>name VARCHAR, label VARCHAR, type VARCHAR, wid VARCHAR, gc INT, t INT, size INT, head BOOLEAN\n"); for (UUID segment : segmentGraph.vertices()) { - writeNode(segment, writer, headGraph.containsVertex(segment), epoch, fileStore.getTracker()); + writeNode(segment, writer, headGraph.containsVertex(segment), epoch, fileStore); } writer.write("edgedef>node1 VARCHAR, node2 VARCHAR, head BOOLEAN\n"); @@ -192,20 +192,20 @@ * Create a regular expression based inclusion filter for segment. * * @param pattern regular expression specifying inclusion of nodes. - * @param tracker the segment tracker of the store acting upon. + * @param store the segment store acting upon. * @return */ public static Predicate createRegExpFilter( @Nonnull String pattern, - @Nonnull final SegmentTracker tracker) { + @Nonnull final SegmentStore store) { final Pattern regExp = compile(checkNotNull(pattern)); - checkNotNull(tracker); + checkNotNull(store); return new Predicate() { @Override public boolean apply(UUID segment) { try { - String info = getSegmentInfo(segment, tracker); + String info = getSegmentInfo(segment, store); if (info == null) { info = "NULL"; } @@ -290,7 +290,7 @@ return parseSegmentGraph(fileStore, roots, Predicates.alwaysTrue(), new Function() { @Override @Nullable public String apply(UUID segmentId) { - Map info = new SegmentInfo(segmentId, fileStore.getTracker()).getInfoMap(); + Map info = new SegmentInfo(segmentId, fileStore).getInfoMap(); String error = info.get("error"); if (error != null) { return "Error"; @@ -446,8 +446,8 @@ return graph; } - private static void writeNode(UUID node, PrintWriter writer, boolean inHead, Date epoch, SegmentTracker tracker) { - SegmentInfo segmentInfo = new SegmentInfo(node, tracker); + private static void writeNode(UUID node, PrintWriter writer, boolean inHead, Date epoch, SegmentStore store) { + SegmentInfo segmentInfo = new SegmentInfo(node, store); if (!segmentInfo.isData()) { writer.write(node + ",b,bulk,b,-1,-1," + inHead + "\n"); } else { @@ -491,19 +491,21 @@ return Long.valueOf(string); } - private static String getSegmentInfo(UUID segment, SegmentTracker tracker) { - return new SegmentInfo(segment, tracker).getInfo(); + private static String getSegmentInfo(UUID segment, SegmentStore store) { + return new SegmentInfo(segment, store).getInfo(); } private static class SegmentInfo { + private final UUID uuid; - private final SegmentTracker tracker; + private final SegmentStore store; + private SegmentId id; - SegmentInfo(UUID uuid, SegmentTracker tracker) { + SegmentInfo(UUID uuid, SegmentStore store) { this.uuid = uuid; - this.tracker = tracker; + this.store = store; } boolean isData() { @@ -512,8 +514,9 @@ SegmentId getSegmentId() { if (id == null) { - id = tracker.getSegmentId( - uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); + long msb = uuid.getMostSignificantBits(); + long lsb = uuid.getLeastSignificantBits(); + id = store.getSegmentId(msb, lsb); } return id; } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java (working copy) @@ -18,7 +18,6 @@ */ package org.apache.jackrabbit.oak.segment; -import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMapWithExpectedSize; import static java.util.Collections.nCopies; @@ -63,9 +62,6 @@ private final ArrayList> references = newArrayList(nCopies(1024, (WeakReference) null)); - @Nonnull - private final SegmentStore store; - private static final Logger LOG = LoggerFactory.getLogger(SegmentIdTable.class); @@ -79,10 +75,6 @@ */ private int entryCount; - SegmentIdTable(@Nonnull SegmentStore store) { - this.store = checkNotNull(store); - } - /** * Get the segment id, and reference it in the weak references map. * @@ -91,7 +83,7 @@ * @return the segment id */ @Nonnull - synchronized SegmentId getSegmentId(long msb, long lsb) { + synchronized SegmentId getSegmentId(long msb, long lsb, SegmentIdMaker maker) { int index = getIndex(lsb); boolean shouldRefresh = false; @@ -110,7 +102,7 @@ reference = references.get(index); } - SegmentId id = new SegmentId(store, msb, lsb); + SegmentId id = maker.makeSegmentId(msb, lsb); references.set(index, new WeakReference(id)); entryCount++; if (entryCount > references.size() * 0.75) { Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java (working copy) @@ -54,4 +54,10 @@ */ void writeSegment(SegmentId id, byte[] bytes, int offset, int length) throws IOException; + SegmentId getSegmentId(long msb, long lsb); + + SegmentId newBulkSegmentId(); + + SegmentId newDataSegmentId(); + } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentTracker.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentTracker.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentTracker.java (working copy) @@ -68,9 +68,9 @@ @Nonnull private final AtomicInteger segmentCounter = new AtomicInteger(); - public SegmentTracker(@Nonnull SegmentStore store) { + public SegmentTracker() { for (int i = 0; i < tables.length; i++) { - tables[i] = new SegmentIdTable(store); + tables[i] = new SegmentIdTable(); } } @@ -103,9 +103,9 @@ * @return the segment id */ @Nonnull - public SegmentId getSegmentId(long msb, long lsb) { + public SegmentId getSegmentId(long msb, long lsb, SegmentIdMaker maker) { int index = ((int) msb) & (tables.length - 1); - return tables[index].getSegmentId(msb, lsb); + return tables[index].getSegmentId(msb, lsb, maker); } /** @@ -113,8 +113,8 @@ * @return the segment id */ @Nonnull - SegmentId newDataSegmentId() { - return newSegmentId(DATA); + public SegmentId newDataSegmentId(SegmentIdMaker maker) { + return newSegmentId(DATA, maker); } /** @@ -122,16 +122,16 @@ * @return the segment id */ @Nonnull - SegmentId newBulkSegmentId() { - return newSegmentId(BULK); + public SegmentId newBulkSegmentId(SegmentIdMaker maker) { + return newSegmentId(BULK, maker); } @Nonnull - private SegmentId newSegmentId(long type) { + private SegmentId newSegmentId(long type, SegmentIdMaker maker) { segmentCounter.incrementAndGet(); long msb = (random.nextLong() & MSB_MASK) | VERSION; long lsb = (random.nextLong() & LSB_MASK) | type; - return getSegmentId(msb, lsb); + return getSegmentId(msb, lsb, maker); } // FIXME OAK-4285: Align cleanup of segment id tables with the new cleanup strategy Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java (working copy) @@ -97,9 +97,6 @@ private final BlobStore blobStore; @Nonnull - private final SegmentTracker tracker; - - @Nonnull private final WriteOperationHandler writeOperationHandler; /** @@ -109,18 +106,15 @@ * @param store store to write to * @param reader segment reader for the {@code store} * @param blobStore the blog store or {@code null} for inlined blobs - * @param tracker segment tracker for {@code store} * @param writeOperationHandler handler for write operations. */ public SegmentWriter(@Nonnull SegmentStore store, @Nonnull SegmentReader reader, @Nullable BlobStore blobStore, - @Nonnull SegmentTracker tracker, @Nonnull WriteOperationHandler writeOperationHandler) { this.store = checkNotNull(store); this.reader = checkNotNull(reader); this.blobStore = blobStore; - this.tracker = checkNotNull(tracker); this.writeOperationHandler = checkNotNull(writeOperationHandler); this.cacheManager = new WriterCacheManager(); } @@ -600,7 +594,7 @@ // write as many full bulk segments as possible while (pos + Segment.MAX_SEGMENT_SIZE <= data.length) { - SegmentId bulkId = tracker.newBulkSegmentId(); + SegmentId bulkId = store.newBulkSegmentId(); store.writeSegment(bulkId, data, pos, Segment.MAX_SEGMENT_SIZE); for (int i = 0; i < Segment.MAX_SEGMENT_SIZE; i += BLOCK_SIZE) { blockIds.add(new RecordId(bulkId, i)); @@ -729,7 +723,7 @@ // Write the data to bulk segments and collect the list of block ids while (n != 0) { - SegmentId bulkId = tracker.newBulkSegmentId(); + SegmentId bulkId = store.newBulkSegmentId(); int len = Segment.align(n, 1 << Segment.RECORD_ALIGN_BITS); LOG.debug("Writing bulk segment {} ({} bytes)", bulkId, n); store.writeSegment(bulkId, data, 0, len); Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriters.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriters.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriters.java (working copy) @@ -38,7 +38,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, @Nonnull Supplier generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriterPool(store, store.getTracker(), store.getReader(), version, name, generation)); } @@ -51,7 +51,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, @Nonnull Supplier generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriterPool(store, store.getTracker(), store.getReader(), version, name, generation)); } @@ -64,7 +64,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, @Nonnull Supplier generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriterPool(store, store.getTracker(), store.getReader(), version, name, generation)); } @@ -77,7 +77,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, int generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriter(store, store.getTracker(), store.getReader(), version, name, generation)); } @@ -90,7 +90,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, int generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriter(store, store.getTracker(), store.getReader(), version, name, generation)); } @@ -103,7 +103,7 @@ @Nonnull SegmentVersion version, @Nonnull String name, int generation) { - return new SegmentWriter(store, store.getReader(), store.getBlobStore(), store.getTracker(), + return new SegmentWriter(store, store.getReader(), store.getBlobStore(), new SegmentBufferWriter(store, store.getTracker(), store.getReader(), version, name, generation)); } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (working copy) @@ -85,6 +85,7 @@ import org.apache.jackrabbit.oak.segment.SegmentGraph.SegmentGraphVisitor; import org.apache.jackrabbit.oak.segment.Compactor; import org.apache.jackrabbit.oak.segment.SegmentId; +import org.apache.jackrabbit.oak.segment.SegmentIdMaker; import org.apache.jackrabbit.oak.segment.SegmentNodeState; import org.apache.jackrabbit.oak.segment.SegmentNodeStore; import org.apache.jackrabbit.oak.segment.SegmentNotFoundException; @@ -224,6 +225,15 @@ @Nonnull private final SegmentCache segmentCache; + private final SegmentIdMaker maker = new SegmentIdMaker() { + + @Override + public SegmentId makeSegmentId(long msb, long lsb) { + return new SegmentId(FileStore.this, msb, lsb); + } + + }; + /** * Create a new instance of a {@link Builder} for a file store. * @param directory directory where the tar files are stored @@ -425,7 +435,7 @@ private FileStore(Builder builder, boolean readOnly) throws IOException { this.version = builder.version; - this.tracker = new SegmentTracker(this); + this.tracker = new SegmentTracker(); this.revisions = builder.revisions; this.blobStore = builder.blobStore; @@ -961,7 +971,7 @@ int minGeneration = getGcGeneration() - gcOptions.getRetainedGenerations() + 1; for (TarReader tarReader : tarReaders) { - tarReader.collectBlobReferences(tracker, collector, minGeneration); + tarReader.collectBlobReferences(this, collector, minGeneration); } } @@ -1143,7 +1153,7 @@ Supplier cancel) throws IOException { if (gcOptions.isOffline()) { - SegmentWriter writer = new SegmentWriter(this, segmentReader, blobStore, tracker, bufferWriter); + SegmentWriter writer = new SegmentWriter(this, segmentReader, blobStore, bufferWriter); return new Compactor(segmentReader, writer, blobStore, cancel, gcOptions) .compact(EMPTY_NODE, head, EMPTY_NODE); } else { @@ -1183,16 +1193,16 @@ List ids = newArrayList(); if (tarWriter != null) { for (UUID uuid : tarWriter.getUUIDs()) { - ids.add(tracker.getSegmentId( - uuid.getMostSignificantBits(), - uuid.getLeastSignificantBits())); + long msb = uuid.getMostSignificantBits(); + long lsb = uuid.getLeastSignificantBits(); + ids.add(getSegmentId(msb, lsb)); } } for (TarReader reader : readers) { for (UUID uuid : reader.getUUIDs()) { - ids.add(tracker.getSegmentId( - uuid.getMostSignificantBits(), - uuid.getLeastSignificantBits())); + long msb = uuid.getMostSignificantBits(); + long lsb = uuid.getLeastSignificantBits(); + ids.add(getSegmentId(msb, lsb)); } } return ids; @@ -1321,7 +1331,7 @@ ByteBuffer buffer = reader.readEntry(msb, lsb); if (buffer != null) { - return new Segment(tracker, segmentReader, id, buffer); + return new Segment(FileStore.this, segmentReader, id, buffer); } } catch (IOException e) { log.warn("Failed to read from tar file {}", reader, e); @@ -1334,7 +1344,7 @@ try { ByteBuffer buffer = tarWriter.readEntry(msb, lsb); if (buffer != null) { - return new Segment(tracker, segmentReader, id, buffer); + return new Segment(FileStore.this, segmentReader, id, buffer); } } catch (IOException e) { log.warn("Failed to read from tar file {}", tarWriter, e); @@ -1357,7 +1367,7 @@ ByteBuffer buffer = reader.readEntry(msb, lsb); if (buffer != null) { - return new Segment(tracker, segmentReader, id, buffer); + return new Segment(FileStore.this, segmentReader, id, buffer); } } catch (IOException e) { log.warn("Failed to read from tar file {}", reader, e); @@ -1401,10 +1411,25 @@ } else { data = ByteBuffer.wrap(buffer, offset, length); } - segmentCache.putSegment(new Segment(tracker, segmentReader, id, data)); + segmentCache.putSegment(new Segment(this, segmentReader, id, data)); } } + @Override + public SegmentId getSegmentId(long msb, long lsb) { + return tracker.getSegmentId(msb, lsb, maker); + } + + @Override + public SegmentId newBulkSegmentId() { + return tracker.newBulkSegmentId(maker); + } + + @Override + public SegmentId newDataSegmentId() { + return tracker.newDataSegmentId(maker); + } + /** * Switch to a new tar writer. * This method may only be called when holding the write lock of {@link #fileStoreLock} @@ -1471,7 +1496,7 @@ private void setRevision(String rootRevision) { fileStoreLock.writeLock().lock(); try { - revisions.setHeadId(RecordId.fromString(tracker, rootRevision)); + revisions.setHeadId(RecordId.fromString(this, rootRevision)); } finally { fileStoreLock.writeLock().unlock(); } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarReader.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarReader.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarReader.java (working copy) @@ -58,6 +58,7 @@ import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector; import org.apache.jackrabbit.oak.segment.SegmentGraph.SegmentGraphVisitor; import org.apache.jackrabbit.oak.segment.SegmentId; +import org.apache.jackrabbit.oak.segment.SegmentStore; import org.apache.jackrabbit.oak.segment.SegmentTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -734,16 +735,16 @@ /** * Collect the references of those blobs that are reachable from any segment with a * generation at or above {@code minGeneration}. - * @param tracker + * @param store * @param collector * @param minGeneration */ - void collectBlobReferences(SegmentTracker tracker, ReferenceCollector collector, int minGeneration) { + void collectBlobReferences(SegmentStore store, ReferenceCollector collector, int minGeneration) { for (TarEntry entry : getEntries()) { if (entry.generation() >= minGeneration) { // FIXME OAK-4201: Add an index of binary references in a tar file // Fetch the blob references from the tar index instead reading them from the segment - SegmentId id = tracker.getSegmentId(entry.msb(), entry.lsb()); + SegmentId id = store.getSegmentId(entry.msb(), entry.lsb()); id.getSegment().collectBlobReferences(collector); } } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarRevisions.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarRevisions.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TarRevisions.java (working copy) @@ -131,7 +131,7 @@ while (persistedId == null && entries.hasNext()) { String entry = entries.next(); try { - RecordId id = RecordId.fromString(tracker, entry); + RecordId id = RecordId.fromString(store, entry); if (store.containsSegment(id.getSegmentId())) { persistedId = id; } else { Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStore.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStore.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStore.java (working copy) @@ -40,6 +40,7 @@ import org.apache.jackrabbit.oak.segment.Revisions; import org.apache.jackrabbit.oak.segment.Segment; import org.apache.jackrabbit.oak.segment.SegmentId; +import org.apache.jackrabbit.oak.segment.SegmentIdMaker; import org.apache.jackrabbit.oak.segment.SegmentNotFoundException; import org.apache.jackrabbit.oak.segment.SegmentReader; import org.apache.jackrabbit.oak.segment.SegmentStore; @@ -50,7 +51,7 @@ public class HttpStore implements SegmentStore { @Nonnull - private final SegmentTracker tracker = new SegmentTracker(this); + private final SegmentTracker tracker = new SegmentTracker(); @Nonnull private final HttpStoreRevisions revisions = new HttpStoreRevisions(this); @@ -66,6 +67,15 @@ private final SegmentReader segmentReader = new CachingSegmentReader( getWriter, revisions, null, DEFAULT_STRING_CACHE_MB); + private final SegmentIdMaker maker = new SegmentIdMaker() { + + @Override + public SegmentId makeSegmentId(long msb, long lsb) { + return new SegmentId(HttpStore.this, msb, lsb); + } + + }; + @Nonnull private final SegmentWriter segmentWriter = pooledSegmentWriter(this, LATEST_VERSION, "sys", Suppliers.ofInstance(0)); @@ -101,6 +111,21 @@ return revisions; } + @Override + public SegmentId getSegmentId(long msb, long lsb) { + return tracker.getSegmentId(msb, lsb, maker); + } + + @Override + public SegmentId newBulkSegmentId() { + return tracker.newBulkSegmentId(maker); + } + + @Override + public SegmentId newDataSegmentId() { + return tracker.newDataSegmentId(maker); + } + /** * Builds a simple URLConnection. This method can be extended to add * authorization headers if needed. @@ -131,7 +156,7 @@ InputStream stream = connection.getInputStream(); try { byte[] data = ByteStreams.toByteArray(stream); - return new Segment(tracker, segmentReader, id, ByteBuffer.wrap(data)); + return new Segment(this, segmentReader, id, ByteBuffer.wrap(data)); } finally { stream.close(); } Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStoreRevisions.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStoreRevisions.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStoreRevisions.java (working copy) @@ -52,7 +52,7 @@ InputStream stream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8)) ) { - return RecordId.fromString(store.getTracker(), reader.readLine()); + return RecordId.fromString(store, reader.readLine()); } } catch (IllegalArgumentException | MalformedURLException e) { throw new IllegalStateException(e); Index: oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/memory/MemoryStore.java =================================================================== --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/memory/MemoryStore.java (revision 1746972) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/memory/MemoryStore.java (working copy) @@ -35,6 +35,7 @@ import org.apache.jackrabbit.oak.segment.Revisions; import org.apache.jackrabbit.oak.segment.Segment; import org.apache.jackrabbit.oak.segment.SegmentId; +import org.apache.jackrabbit.oak.segment.SegmentIdMaker; import org.apache.jackrabbit.oak.segment.SegmentNotFoundException; import org.apache.jackrabbit.oak.segment.SegmentReader; import org.apache.jackrabbit.oak.segment.SegmentStore; @@ -48,7 +49,7 @@ public class MemoryStore implements SegmentStore { @Nonnull - private final SegmentTracker tracker = new SegmentTracker(this); + private final SegmentTracker tracker = new SegmentTracker(); @Nonnull private final MemoryStoreRevisions revisions; @@ -59,6 +60,15 @@ @Nonnull private final SegmentWriter segmentWriter; + private final SegmentIdMaker maker = new SegmentIdMaker() { + + @Override + public SegmentId makeSegmentId(long msb, long lsb) { + return new SegmentId(MemoryStore.this, msb, lsb); + } + + }; + private final ConcurrentMap segments = Maps.newConcurrentMap(); @@ -112,12 +122,27 @@ } @Override + public SegmentId getSegmentId(long msb, long lsb) { + return tracker.getSegmentId(msb, lsb, maker); + } + + @Override + public SegmentId newBulkSegmentId() { + return tracker.newBulkSegmentId(maker); + } + + @Override + public SegmentId newDataSegmentId() { + return tracker.newDataSegmentId(maker); + } + + @Override public void writeSegment( SegmentId id, byte[] data, int offset, int length) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(length); buffer.put(data, offset, length); buffer.rewind(); - Segment segment = new Segment(tracker, segmentReader, id, buffer); + Segment segment = new Segment(this, segmentReader, id, buffer); if (segments.putIfAbsent(id, segment) != null) { throw new IOException("Segment override: " + id); } Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java (working copy) @@ -149,10 +149,9 @@ @Test public void testListWithLotsOfReferences() throws IOException { // OAK-1184 - SegmentTracker factory = store.getTracker(); List list = newArrayList(); for (int i = 0; i < 1000; i++) { - list.add(new RecordId(factory.newBulkSegmentId(), 0)); + list.add(new RecordId(store.newBulkSegmentId(), 0)); } writer.writeList(list); } Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentGraphTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentGraphTest.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentGraphTest.java (working copy) @@ -146,7 +146,7 @@ public void testSegmentGraphWithFilter() throws IOException { ReadOnlyStore store = FileStore.builder(getStoreFolder()).buildReadOnly(); try { - Predicate filter = createRegExpFilter(".*(writer2|writer3).*", store.getTracker()); + Predicate filter = createRegExpFilter(".*(writer2|writer3).*", store); Graph segmentGraph = parseSegmentGraph(store, filter); assertEquals(filteredSegments, newHashSet(segmentGraph.vertices())); Map> map = newHashMap(); Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdFactoryTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdFactoryTest.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdFactoryTest.java (working copy) @@ -39,25 +39,25 @@ @Test public void segmentIdType() { - assertTrue(tracker.newDataSegmentId().isDataSegmentId()); - assertTrue(tracker.newBulkSegmentId().isBulkSegmentId()); + assertTrue(store.newDataSegmentId().isDataSegmentId()); + assertTrue(store.newBulkSegmentId().isBulkSegmentId()); - assertFalse(tracker.newDataSegmentId().isBulkSegmentId()); - assertFalse(tracker.newBulkSegmentId().isDataSegmentId()); + assertFalse(store.newDataSegmentId().isBulkSegmentId()); + assertFalse(store.newBulkSegmentId().isDataSegmentId()); } @Test public void internedSegmentIds() { - assertTrue(tracker.getSegmentId(0, 0) == tracker.getSegmentId(0, 0)); - assertTrue(tracker.getSegmentId(1, 2) == tracker.getSegmentId(1, 2)); - assertTrue(tracker.getSegmentId(1, 2) != tracker.getSegmentId(3, 4)); + assertTrue(store.getSegmentId(0, 0) == store.getSegmentId(0, 0)); + assertTrue(store.getSegmentId(1, 2) == store.getSegmentId(1, 2)); + assertTrue(store.getSegmentId(1, 2) != store.getSegmentId(3, 4)); } @Test public void referencedSegmentIds() throws InterruptedException { - SegmentId a = tracker.newDataSegmentId(); - SegmentId b = tracker.newBulkSegmentId(); - SegmentId c = tracker.newDataSegmentId(); + SegmentId a = store.newDataSegmentId(); + SegmentId b = store.newBulkSegmentId(); + SegmentId c = store.newDataSegmentId(); Set ids = tracker.getReferencedSegmentIds(); assertTrue(ids.contains(a)); @@ -65,7 +65,7 @@ assertTrue(ids.contains(c)); // the returned set is a snapshot in time, not continuously updated - assertFalse(ids.contains(tracker.newBulkSegmentId())); + assertFalse(ids.contains(store.newBulkSegmentId())); } /** @@ -75,8 +75,8 @@ */ // @Test public void garbageCollection() { - SegmentId a = tracker.newDataSegmentId(); - SegmentId b = tracker.newBulkSegmentId(); + SegmentId a = store.newDataSegmentId(); + SegmentId b = store.newBulkSegmentId(); // generate lots of garbage copies of an UUID to get the // garbage collector to reclaim also the original instance @@ -102,9 +102,9 @@ byte[] buffer = new byte[segment.size()]; segment.readBytes(Segment.MAX_SEGMENT_SIZE - segment.size(), buffer, 0, segment.size()); - SegmentId id = tracker.newDataSegmentId(); + SegmentId id = store.newDataSegmentId(); ByteBuffer data = ByteBuffer.wrap(buffer); - Segment s = new Segment(store.getTracker(), store.getReader(), id, data); + Segment s = new Segment(store, store.getReader(), id, data); s.getRefId(1); } @@ -113,9 +113,9 @@ */ @Test(expected = IllegalStateException.class) public void bulkAIOOBE() { - SegmentId id = tracker.newBulkSegmentId(); + SegmentId id = store.newBulkSegmentId(); ByteBuffer data = ByteBuffer.allocate(4); - Segment s = new Segment(store.getTracker(), store.getReader(), id, data); + Segment s = new Segment(store, store.getReader(), id, data); s.getRefId(1); } Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableBenchmark.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableBenchmark.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableBenchmark.java (working copy) @@ -25,6 +25,18 @@ import org.apache.jackrabbit.oak.segment.memory.MemoryStore; public class SegmentIdTableBenchmark { + + private static SegmentIdMaker newSegmentIdMaker(final SegmentStore store) { + return new SegmentIdMaker() { + + @Override + public SegmentId makeSegmentId(long msb, long lsb) { + return new SegmentId(store, msb, lsb); + } + + }; + } + public static void main(String... args) throws IOException { test(); test(); @@ -47,10 +59,11 @@ time = System.currentTimeMillis(); MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + SegmentIdMaker maker = newSegmentIdMaker(store); + final SegmentIdTable tbl = new SegmentIdTable(); for (int i = 0; i < repeat; i++) { for (int j = 0; j < count; j++) { - tbl.getSegmentId(j, array[j]); + tbl.getSegmentId(j, array[j], maker); } } time = System.currentTimeMillis() - time; Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableTest.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableTest.java (working copy) @@ -40,17 +40,32 @@ public class SegmentIdTableTest { + private static SegmentIdMaker newSegmentIdMaker(final SegmentStore store) { + return new SegmentIdMaker() { + + @Override + public SegmentId makeSegmentId(long msb, long lsb) { + return new SegmentId(store, msb, lsb); + } + + }; + } + + private static SegmentIdMaker newSegmentIdMaker() throws IOException { + return newSegmentIdMaker(new MemoryStore()); + } + /** * OAK-2752 */ @Test public void endlessSearchLoop() throws IOException { - MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + final SegmentIdMaker maker = newSegmentIdMaker(); + final SegmentIdTable tbl = new SegmentIdTable(); List refs = new ArrayList(); for (int i = 0; i < 1024; i++) { - refs.add(tbl.getSegmentId(i, i % 64)); + refs.add(tbl.getSegmentId(i, i % 64, maker)); } Callable c = new Callable() { @@ -58,7 +73,7 @@ @Override public SegmentId call() throws Exception { // (2,1) doesn't exist - return tbl.getSegmentId(2, 1); + return tbl.getSegmentId(2, 1, maker); } }; Future f = Executors.newSingleThreadExecutor().submit(c); @@ -75,13 +90,13 @@ @Test public void randomized() throws IOException { - MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + SegmentIdMaker maker = newSegmentIdMaker(); + final SegmentIdTable tbl = new SegmentIdTable(); List refs = new ArrayList(); Random r = new Random(1); for (int i = 0; i < 16 * 1024; i++) { - refs.add(tbl.getSegmentId(r.nextLong(), r.nextLong())); + refs.add(tbl.getSegmentId(r.nextLong(), r.nextLong(), maker)); } assertEquals(16 * 1024, tbl.getEntryCount()); assertEquals(16 * 2048, tbl.getMapSize()); @@ -89,7 +104,7 @@ r = new Random(1); for (int i = 0; i < 16 * 1024; i++) { - refs.add(tbl.getSegmentId(r.nextLong(), r.nextLong())); + refs.add(tbl.getSegmentId(r.nextLong(), r.nextLong(), maker)); assertEquals(16 * 1024, tbl.getEntryCount()); assertEquals(16 * 2048, tbl.getMapSize()); assertEquals(5, tbl.getMapRebuildCount()); @@ -98,13 +113,13 @@ @Test public void clearTable() throws IOException { - MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + SegmentIdMaker maker = newSegmentIdMaker(); + final SegmentIdTable tbl = new SegmentIdTable(); List refs = new ArrayList(); int originalCount = 8; for (int i = 0; i < originalCount; i++) { - refs.add(tbl.getSegmentId(i, i % 2)); + refs.add(tbl.getSegmentId(i, i % 2, maker)); } assertEquals(originalCount, tbl.getEntryCount()); assertEquals(0, tbl.getMapRebuildCount()); @@ -120,9 +135,9 @@ for (SegmentId id : refs) { if (id.getMostSignificantBits() >= 4) { - SegmentId id2 = tbl.getSegmentId( - id.getMostSignificantBits(), - id.getLeastSignificantBits()); + long msb = id.getMostSignificantBits(); + long lsb = id.getLeastSignificantBits(); + SegmentId id2 = tbl.getSegmentId(msb, lsb, maker); List list = tbl.getRawSegmentIdList(); if (list.size() != new HashSet(list).size()) { Collections.sort(list); @@ -135,14 +150,14 @@ @Test public void justHashCollisions() throws IOException { - MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + SegmentIdMaker maker = newSegmentIdMaker(); + final SegmentIdTable tbl = new SegmentIdTable(); List refs = new ArrayList(); int originalCount = 1024; for (int i = 0; i < originalCount; i++) { // modulo 128 to ensure we have conflicts - refs.add(tbl.getSegmentId(i, i % 128)); + refs.add(tbl.getSegmentId(i, i % 128, maker)); } assertEquals(originalCount, tbl.getEntryCount()); assertEquals(1, tbl.getMapRebuildCount()); @@ -159,14 +174,14 @@ @Test public void gc() throws IOException { - MemoryStore store = new MemoryStore(); - final SegmentIdTable tbl = new SegmentIdTable(store); + SegmentIdMaker maker = newSegmentIdMaker(); + final SegmentIdTable tbl = new SegmentIdTable(); List refs = new ArrayList(); int originalCount = 1024; for (int i = 0; i < originalCount; i++) { // modulo 128 to ensure we have conflicts - refs.add(tbl.getSegmentId(i, i % 128)); + refs.add(tbl.getSegmentId(i, i % 128, maker)); } assertEquals(originalCount, tbl.getEntryCount()); assertEquals(1, tbl.getMapRebuildCount()); @@ -182,7 +197,9 @@ System.gc(); for (SegmentId id : refs) { - SegmentId id2 = tbl.getSegmentId(id.getMostSignificantBits(), id.getLeastSignificantBits()); + long msb = id.getMostSignificantBits(); + long lsb = id.getLeastSignificantBits(); + SegmentId id2 = tbl.getSegmentId(msb, lsb, maker); assertTrue(id2 == id); } // because we found each entry, we expect the refresh count is the same @@ -192,7 +209,7 @@ // it is supposed to detect that entries were removed, // and force a refresh, which would get rid of the unreferenced ids for (int i = 0; i < 10; i++) { - tbl.getSegmentId(i, i); + tbl.getSegmentId(i, i, maker); } if (tbl.getEntryCount() < originalCount) { Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentParserTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentParserTest.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentParserTest.java (working copy) @@ -401,7 +401,7 @@ @Test public void emptyList() { - RecordId listId = newRecordId(store.getTracker(), new Random()); + RecordId listId = newRecordId(store, new Random()); ListInfo listInfo = new TestParser(store.getReader(), "emptyList").parseList(null, listId, 0); assertEquals(listId, listInfo.listId); assertEquals(0, listInfo.count); Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/TestUtils.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/TestUtils.java (revision 1746972) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/TestUtils.java (working copy) @@ -33,8 +33,8 @@ public final class TestUtils { private TestUtils() {} - public static RecordId newRecordId(SegmentTracker factory, Random random) { - SegmentId id = factory.newDataSegmentId(); + public static RecordId newRecordId(SegmentStore store, Random random) { + SegmentId id = store.newDataSegmentId(); RecordId r = new RecordId(id, newValidOffset(random)); return r; } @@ -57,22 +57,22 @@ * Create a random map of record ids. * * @param rnd - * @param tracker + * @param store * @param segmentCount number of segments * @param entriesPerSegment number of records per segment * @return map of record ids */ - public static Map randomRecordIdMap(Random rnd, SegmentTracker tracker, + public static Map randomRecordIdMap(Random rnd, SegmentStore store, int segmentCount, int entriesPerSegment) { Map map = newHashMap(); for (int i = 0; i < segmentCount; i++) { - SegmentId id = tracker.newDataSegmentId(); + SegmentId id = store.newDataSegmentId(); int offset = MAX_SEGMENT_SIZE; for (int j = 0; j < entriesPerSegment; j++) { offset = newValidOffset(rnd, (entriesPerSegment - j) << RECORD_ALIGN_BITS, offset); RecordId before = new RecordId(id, offset); RecordId after = new RecordId( - tracker.newDataSegmentId(), + store.newDataSegmentId(), newValidOffset(rnd, 0, MAX_SEGMENT_SIZE)); map.put(before, after); }