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 1762406) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (working copy) @@ -67,7 +67,7 @@ * is used for identifying the segment and two for the record offset * within that segment. */ - static final int RECORD_ID_BYTES = 8 + 8 + 2; + static final int RECORD_ID_BYTES = 4 + 2; /** * The limit on segment references within one segment. Since record @@ -140,7 +140,7 @@ @Nonnull private final SegmentVersion version; - private final Map recordIdCache = newHashMap(); + private final Map segmentIdCache = newHashMap(); /** * Unpacks a 4 byte aligned segment offset. @@ -386,27 +386,39 @@ } private RecordId internalReadRecordId(int pos) { - RecordId recordId = recordIdCache.get(pos); + SegmentId segmentId = dereferenceSegmentId(data.getInt(pos)); + int offset = (data.getShort(pos + 4) & 0xffff) << RECORD_ALIGN_BITS; + return new RecordId(segmentId, offset); + } - if (recordId != null) { - return recordId; + private SegmentId dereferenceSegmentId(int reference) { + if (reference == 0) { + return id; } - synchronized (recordIdCache) { - recordId = recordIdCache.get(pos); + SegmentId id = segmentIdCache.get(reference); - if (recordId != null) { - return recordId; + if (id != null) { + return id; + } + + synchronized (segmentIdCache) { + id = segmentIdCache.get(reference); + + if (id != null) { + return id; } - long msb = data.getLong(pos); - long lsb = data.getLong(pos + 8); - int offset = (data.getShort(pos + 16) & 0xffff) << RECORD_ALIGN_BITS; - recordId = new RecordId(store.newSegmentId(msb, lsb), offset); + int position = data.position() + HEADER_SIZE + (reference - 1) * 16; - recordIdCache.put(pos, recordId); + long msb = data.getLong(position); + long lsb = data.getLong(position + 8); - return recordId; + id = store.newSegmentId(msb, lsb); + + segmentIdCache.put(reference, id); + + return id; } } 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 1762406) +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (working copy) @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Maps.newLinkedHashMap; import static com.google.common.collect.Sets.newHashSet; import static java.lang.System.arraycopy; @@ -112,7 +113,7 @@ */ private final Map roots = newLinkedHashMap(); - private final Set referencedSegmentIds = newHashSet(); + private final Map referencedSegmentIds = newHashMap(); @Nonnull private final SegmentStore store; @@ -286,21 +287,38 @@ checkState(offset == align(offset, 1 << Segment.RECORD_ALIGN_BITS)); SegmentId segmentId = recordId.getSegmentId(); + checkGCGeneration(segmentId); - writeLong(segmentId.getMostSignificantBits()); - writeLong(segmentId.getLeastSignificantBits()); - writeShort((short)((offset >> Segment.RECORD_ALIGN_BITS) & 0xffff)); + writeInt(writeSegmentIdReference(segmentId)); + writeShort((short) ((offset >> Segment.RECORD_ALIGN_BITS) & 0xffff)); - if (!segmentId.equals(segment.getSegmentId())) { - referencedSegmentIds.add(segmentId); - } - statistics.recordIdCount++; dirty = true; } + private int writeSegmentIdReference(SegmentId id) { + if (id.equals(segment.getSegmentId())) { + return 0; + } + + Integer reference = referencedSegmentIds.get(id); + + if (reference != null) { + return reference; + } + + reference = referencedSegmentIds.size() + 1; + referencedSegmentIds.put(id, reference); + + BinaryUtils.writeInt(buffer, Segment.REFERENCED_SEGMENT_ID_COUNT_OFFSET, reference); + BinaryUtils.writeLong(buffer, HEADER_SIZE + reference * 16 - 16, id.getMostSignificantBits()); + BinaryUtils.writeLong(buffer, HEADER_SIZE + reference * 16 - 8, id.getLeastSignificantBits()); + + return reference; + } + /** * Check that the generation of a segment matches the generation of this writer and logs * a warning otherwise. @@ -350,7 +368,6 @@ BinaryUtils.writeShort(buffer, Segment.ROOT_COUNT_OFFSET, (short) rootcount); int referencedSegmentIdCount = referencedSegmentIds.size(); - BinaryUtils.writeInt(buffer, Segment.REFERENCED_SEGMENT_ID_COUNT_OFFSET, referencedSegmentIdCount); statistics.segmentIdCount = referencedSegmentIdCount; int totalLength = align(HEADER_SIZE + referencedSegmentIdCount * 16 + rootcount * 3 + length, 16); @@ -361,7 +378,7 @@ statistics.size = length = totalLength; - int pos = HEADER_SIZE; + int pos = HEADER_SIZE + referencedSegmentIdCount * 16; if (pos + length <= buffer.length) { // the whole segment fits to the space *after* the referenced // segment identifiers we've already written, so we can safely @@ -377,11 +394,6 @@ length = buffer.length; } - for (SegmentId id : referencedSegmentIds) { - pos = BinaryUtils.writeLong(buffer, pos, id.getMostSignificantBits()); - pos = BinaryUtils.writeLong(buffer, pos, id.getLeastSignificantBits()); - } - for (Map.Entry entry : roots.entrySet()) { pos = BinaryUtils.writeByte(buffer, pos, (byte) entry.getValue().ordinal()); pos = BinaryUtils.writeShort(buffer, pos, (short) (entry.getKey().getOffset() >> Segment.RECORD_ALIGN_BITS)); @@ -455,7 +467,7 @@ // Adjust the estimation of the new referenced segment ID count. for (SegmentId segmentId : segmentIds) { - if (referencedSegmentIds.contains(segmentId.asUUID())) { + if (referencedSegmentIds.containsKey(segmentId)) { referencedIdCount--; } } Index: oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/MBeanTest.java =================================================================== --- oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/MBeanTest.java (revision 1762406) +++ oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/MBeanTest.java (working copy) @@ -195,7 +195,7 @@ assertEquals("1", jmxServer.invoke(clientStatus, "calcSecondsSinceLastSuccess", null, null).toString()); assertEquals(new Long(1), jmxServer.getAttribute(connectionStatus, "TransferredSegments")); - assertEquals(new Long(208), jmxServer.getAttribute(connectionStatus, "TransferredSegmentBytes")); + assertEquals(new Long(128), jmxServer.getAttribute(connectionStatus, "TransferredSegmentBytes")); // stop the master jmxServer.invoke(serverStatus, "stop", null, null);