Author: jukka
Date: Thu Sep 26 19:22:43 2013
New Revision: 1526651
URL: http://svn.apache.org/r1526651
Log:
OAK-1031: SegmentMK: Fewer segment lookups
Include a Segment reference in the Record base class to avoid extra lookups.
The reference is lazily adjusted to point to the correct segment to avoid
potentially costly pre-loading of all referenced segments that might not
end up being read at all.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/BlockRecord.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Record.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentStream.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/BlockRecord.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/BlockRecord.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/BlockRecord.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/BlockRecord.java
Thu Sep 26 19:22:43 2013
@@ -24,8 +24,8 @@ class BlockRecord extends Record {
private final int size;
- BlockRecord(RecordId id, int size) {
- super(id);
+ BlockRecord(Segment segment, RecordId id, int size) {
+ super(segment, id);
this.size = size;
}
@@ -34,16 +34,13 @@ class BlockRecord extends Record {
* read starting from the given position within this block. The number
* of bytes read is returned.
*
- * @param reader segment reader
* @param position position within this block
* @param buffer target buffer
* @param offset offset within the target buffer
* @param length maximum number of bytes to read
* @return number of bytes that could be read
*/
- public int read(
- SegmentReader reader, int position,
- byte[] buffer, int offset, int length) {
+ public int read(int position, byte[] buffer, int offset, int length) {
checkElementIndex(position, size);
checkNotNull(buffer);
checkPositionIndexes(offset, offset + length, buffer.length);
@@ -52,7 +49,7 @@ class BlockRecord extends Record {
length = size - position;
}
if (length > 0) {
- reader.readBytes(getRecordId(), position, buffer, offset, length);
+ getSegment().readBytes(getOffset(position), buffer, offset,
length);
}
return length;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
Thu Sep 26 19:22:43 2013
@@ -27,8 +27,8 @@ class ListRecord extends Record {
private final int bucketSize;
- ListRecord(RecordId id, int size) {
- super(id);
+ ListRecord(Segment segment, RecordId id, int size) {
+ super(segment, id);
checkArgument(size >= 0);
this.size = size;
@@ -51,10 +51,9 @@ class ListRecord extends Record {
} else {
int bucketIndex = index / bucketSize;
int bucketOffset = index % bucketSize;
- RecordId bucketId = reader.readRecordId(
- getRecordId(), bucketIndex * Segment.RECORD_ID_BYTES);
- ListRecord bucket =
- new ListRecord(bucketId, bucketSize);
+ Segment segment = getSegment();
+ RecordId bucketId = segment.readRecordId(getOffset(0,
bucketIndex));
+ ListRecord bucket = new ListRecord(segment, bucketId, bucketSize);
return bucket.getEntry(reader, bucketOffset);
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
Thu Sep 26 19:22:43 2013
@@ -23,6 +23,8 @@ import static com.google.common.collect.
import static java.lang.Integer.highestOneBit;
import static java.lang.Integer.numberOfTrailingZeros;
+import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.Set;
import java.util.UUID;
@@ -83,7 +85,8 @@ abstract class MapRecord extends Record
protected final int level;
protected MapRecord(SegmentStore store, RecordId id, int size, int level) {
- super(checkNotNull(id));
+ // FIXME: ugly hack
+ super(new Segment(store, UUID.randomUUID(), ByteBuffer.allocate(0),
Collections.<UUID>emptyList()), checkNotNull(id));
this.store = checkNotNull(store);
this.size = checkElementIndex(size, MAX_SIZE);
this.level = checkPositionIndex(level, MAX_NUMBER_OF_LEVELS);
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Record.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Record.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Record.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Record.java
Thu Sep 26 19:22:43 2013
@@ -16,18 +16,82 @@
*/
package org.apache.jackrabbit.oak.plugins.segment;
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+
/**
* Record within a segment.
*/
class Record {
/**
- * Identifier of this record.
+ * The segment that contains this record, or initially some other segment
+ * in the same store. The reference is lazily updated when the
+ * {@link #getSegment()} method is first called to prevent the potentially
+ * costly pre-loading of segments that might actually not be needed.
+ */
+ private Segment segment;
+
+ /**
+ * Identifier of the segment that contains this record. The value of
+ * this identifier never changes, but the exact instance reference may
+ * get updated by the {@link #getSegment()} method to indicate that
+ * lazy initialization has happened.
*/
- private final RecordId id;
+ private UUID uuid;
- protected Record(RecordId id) {
- this.id = id;
+ /**
+ * Segment offset of this record.
+ */
+ private final int offset;
+
+ /**
+ * Creates a new object for the identified record. The segment from which
+ * the record identifier was read is also given as it either directly
+ * contains the identified record (common case) or can be used to look
+ * up the segment that contains the record.
+ *
+ * @param segment from which the record identifier was read
+ * @param id record identified
+ */
+ protected Record(@Nonnull Segment segment, @Nonnull RecordId id) {
+ this.segment = checkNotNull(segment);
+
+ checkNotNull(id);
+ if (equal(id.getSegmentId(), segment.getSegmentId())) {
+ this.uuid = segment.getSegmentId();
+ } else {
+ this.uuid = id.getSegmentId();
+ }
+ this.offset = id.getOffset();
+ }
+
+ // TODO: remove this ugly hack
+ protected Record(SegmentStore store, RecordId id) {
+ this(new Segment(
+ store, UUID.randomUUID(),
+ ByteBuffer.allocate(0), Collections.<UUID>emptyList()), id);
+ }
+
+ /**
+ * Returns the segment that contains this record.
+ *
+ * @return segment that contains this record
+ */
+ protected synchronized Segment getSegment() {
+ if (uuid != segment.getSegmentId()) {
+ segment = segment.getSegment(uuid);
+ checkState(uuid.equals(segment.getSegmentId()));
+ uuid = segment.getSegmentId();
+ }
+ return segment;
}
/**
@@ -35,8 +99,8 @@ class Record {
*
* @return record identifier
*/
- public RecordId getRecordId() {
- return id;
+ public synchronized RecordId getRecordId() {
+ return new RecordId(uuid, offset);
}
/**
@@ -44,8 +108,8 @@ class Record {
*
* @return segment offset of this record
*/
- protected int getOffset() {
- return id.getOffset();
+ protected final int getOffset() {
+ return offset;
}
/**
@@ -54,7 +118,7 @@ class Record {
* @param position byte position within this record
* @return segment offset of the given byte position
*/
- protected int getOffset(int position) {
+ protected final int getOffset(int position) {
return getOffset() + position;
}
@@ -67,7 +131,7 @@ class Record {
* @param ids number of record identifiers before the position
* @return segment offset of the specified byte position
*/
- protected int getOffset(int bytes, int ids) {
+ protected final int getOffset(int bytes, int ids) {
return getOffset(bytes + ids * Segment.RECORD_ID_BYTES);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.java
Thu Sep 26 19:22:43 2013
@@ -152,6 +152,15 @@ public class Segment {
}
/**
+ * Returns the identified segment.
+ *
+ * @param uuid segment identifier
+ */
+ Segment getSegment(UUID uuid) {
+ return store.readSegment(uuid);
+ }
+
+ /**
* Reads the given number of bytes starting from the given position
* in this segment.
*
@@ -219,7 +228,7 @@ public class Segment {
} else if (length < Integer.MAX_VALUE) {
int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
ListRecord list =
- new ListRecord(internalReadRecordId(pos + 8), size);
+ new ListRecord(this, internalReadRecordId(pos + 8), size);
SegmentStream stream = new SegmentStream(
store, new RecordId(uuid, offset), list, length);
try {
@@ -340,7 +349,8 @@ public class Segment {
return new SegmentStream(id, inline);
} else {
int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
- ListRecord list = new ListRecord(internalReadRecordId(pos + 8),
size);
+ ListRecord list =
+ new ListRecord(this, internalReadRecordId(pos + 8), size);
return new SegmentStream(store, id, list, length);
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
Thu Sep 26 19:22:43 2013
@@ -56,14 +56,14 @@ class SegmentPropertyState extends Abstr
private ListRecord getValueList() {
RecordId listId = recordId;
int size = 1;
+ Segment segment = store.readSegment(recordId.getSegmentId());
if (isArray()) {
- Segment segment = store.readSegment(recordId.getSegmentId());
size = segment.readInt(recordId.getOffset());
if (size > 0) {
listId = segment.readRecordId(recordId.getOffset() + 4);
}
}
- return new ListRecord(listId, size);
+ return new ListRecord(segment, listId, size);
}
Map<String, RecordId> getValueRecords() {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentReader.java
Thu Sep 26 19:22:43 2013
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
public class SegmentReader {
@@ -57,19 +56,6 @@ public class SegmentReader {
return segment.readInt(recordId.getOffset() + position);
}
- public void readBytes(
- RecordId recordId, int position,
- byte[] buffer, int offset, int length) {
- checkNotNull(recordId);
- checkArgument(position >= 0);
- checkNotNull(buffer);
- checkPositionIndexes(offset, offset + length, buffer.length);
-
- Segment segment = store.readSegment(recordId.getSegmentId());
- segment.readBytes(
- recordId.getOffset() + position, buffer, offset, length);
- }
-
public RecordId readRecordId(RecordId recordId, int position) {
checkNotNull(recordId);
checkArgument(position >= 0);
@@ -82,21 +68,15 @@ public class SegmentReader {
checkNotNull(recordId);
checkArgument(numberOfEntries >= 0);
+ Segment segment = store.readSegment(recordId.getSegmentId());
if (numberOfEntries > 0) {
- Segment segment = store.readSegment(recordId.getSegmentId());
RecordId id = segment.readRecordId(recordId.getOffset());
- return new ListRecord(id, numberOfEntries);
+ return new ListRecord(segment, id, numberOfEntries);
} else {
- return new ListRecord(recordId, numberOfEntries);
+ return new ListRecord(segment, recordId, numberOfEntries);
}
}
- public BlockRecord readBlock(RecordId recordId, int size) {
- checkNotNull(recordId);
- checkArgument(size > 0);
- return new BlockRecord(recordId, size);
- }
-
SegmentStore getStore() {
return store;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentStream.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentStream.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentStream.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentStream.java
Thu Sep 26 19:22:43 2013
@@ -157,9 +157,11 @@ public class SegmentStream extends Input
}
SegmentReader reader = new SegmentReader(store);
- BlockRecord block = reader.readBlock(
- blocks.getEntry(reader, blockIndex), BLOCK_SIZE);
- len = block.read(reader, blockOffset, b, off, len);
+ BlockRecord block = new BlockRecord(
+ blocks.getSegment(),
+ blocks.getEntry(reader, blockIndex),
+ BLOCK_SIZE);
+ len = block.read(blockOffset, b, off, len);
position += len;
return len;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java?rev=1526651&r1=1526650&r2=1526651&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
Thu Sep 26 19:22:43 2013
@@ -26,12 +26,14 @@ import static org.junit.Assert.assertTru
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.UUID;
import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -50,6 +52,10 @@ public class RecordTest {
private SegmentStore store = new MemoryStore();
+ private Segment segment = new Segment(
+ store, UUID.randomUUID(),
+ ByteBuffer.allocate(0), Collections.<UUID>emptyList());
+
private SegmentReader reader = new SegmentReader(store);
private SegmentWriter writer = store.getWriter();
@@ -59,20 +65,20 @@ public class RecordTest {
@Test
public void testBlockRecord() {
RecordId blockId = writer.writeBlock(bytes, 0, bytes.length);
- BlockRecord block = new BlockRecord(blockId, bytes.length);
+ BlockRecord block = new BlockRecord(segment, blockId, bytes.length);
// Check reading with all valid positions and lengths
for (int n = 1; n < bytes.length; n++) {
for (int i = 0; i + n <= bytes.length; i++) {
Arrays.fill(bytes, i, i + n, (byte) '.');
- assertEquals(n, block.read(reader, i, bytes, i, n));
+ assertEquals(n, block.read(i, bytes, i, n));
assertEquals(hello, new String(bytes, Charsets.UTF_8));
}
}
// Check reading with a too long length
byte[] large = new byte[bytes.length * 2];
- assertEquals(bytes.length, block.read(reader, 0, large, 0,
large.length));
+ assertEquals(bytes.length, block.read(0, large, 0, large.length));
assertEquals(hello, new String(large, 0, bytes.length,
Charsets.UTF_8));
}
@@ -104,7 +110,7 @@ public class RecordTest {
private ListRecord writeList(int size, RecordId id) {
List<RecordId> list = Collections.nCopies(size, id);
- return new ListRecord(writer.writeList(list), size);
+ return new ListRecord(segment, writer.writeList(list), size);
}
@Test