Author: jukka
Date: Thu Nov 7 18:50:12 2013
New Revision: 1539759
URL: http://svn.apache.org/r1539759
Log:
OAK-1152: SegmentMK: Improved debuggability
Include header information in non-bulk segments
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordId.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/SegmentWriter.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordId.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordId.java?rev=1539759&r1=1539758&r2=1539759&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordId.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/RecordId.java
Thu Nov 7 18:50:12 2013
@@ -42,7 +42,7 @@ public final class RecordId implements C
public RecordId(UUID segmentId, int offset) {
checkArgument(offset < Segment.MAX_SEGMENT_SIZE);
- checkArgument((offset & (Segment.RECORD_ALIGN_BYTES - 1)) == 0);
+ checkArgument(offset == Segment.align(offset));
this.segmentId = checkNotNull(segmentId);
this.offset = offset;
}
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=1539759&r1=1539758&r2=1539759&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 Nov 7 18:50:12 2013
@@ -54,8 +54,12 @@ public class Segment {
* The number of bytes (or bits of address space) to use for the
* alignment boundary of segment records.
*/
- static final int RECORD_ALIGN_BITS = 2;
- static final int RECORD_ALIGN_BYTES = 1 << RECORD_ALIGN_BITS; // 4
+ static final int RECORD_ALIGN_BITS = 2; // align at the four-byte boundary
+
+ static int align(int value) {
+ int mask = -1 << RECORD_ALIGN_BITS;
+ return (value + ~mask) & mask;
+ }
/**
* Maximum segment size. Record identifiers are stored as three-byte
@@ -96,10 +100,22 @@ public class Segment {
private final ByteBuffer data;
+ private final int refposition;
+
public Segment(SegmentStore store, UUID uuid, ByteBuffer data) {
this.store = checkNotNull(store);
this.uuid = checkNotNull(uuid);
this.data = checkNotNull(data);
+
+ if (data.capacity() > 0
+ && data.capacity() < Segment.MAX_SEGMENT_SIZE) {
+ // so skip the header parts of a normal non-bulk, non-empty segment
+ int roots = data.getShort(data.position() + 1) & 0xffff;
+ int headerSize = 3 + roots * 3;
+ this.refposition = data.position() + align(headerSize);
+ } else {
+ this.refposition = data.position();
+ }
}
/**
@@ -176,7 +192,7 @@ public class Segment {
UUID refid;
int refpos = data.get(pos) & 0xff;
if (refpos != 0xff) {
- refpos = data.position() + refpos * 16;
+ refpos = refposition + refpos * 16;
refid = new UUID(data.getLong(refpos), data.getLong(refpos + 8));
} else {
refid = uuid;
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java?rev=1539759&r1=1539758&r2=1539759&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
Thu Nov 7 18:50:12 2013
@@ -32,6 +32,7 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.api.Type.NAMES;
import static
org.apache.jackrabbit.oak.plugins.segment.MapRecord.BUCKETS_PER_LEVEL;
import static
org.apache.jackrabbit.oak.plugins.segment.Segment.MAX_SEGMENT_SIZE;
+import static org.apache.jackrabbit.oak.plugins.segment.Segment.align;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -108,7 +109,7 @@ public class SegmentWriter {
* The set of root records (i.e. ones not referenced by other records)
* in this segment.
*/
- private final Map<RecordId, RecordType> roots = newHashMap();
+ private final Map<RecordId, RecordType> roots = newLinkedHashMap();
/**
* The segment write buffer, filled from the end to the beginning
@@ -138,14 +139,37 @@ public class SegmentWriter {
new Segment(store, UUID.randomUUID(), ByteBuffer.allocate(0));
}
+ private void writeSegmentHeader(ByteBuffer b) {
+ int p = b.position();
+
+ b.put((byte) refids.size());
+ b.putShort((short) roots.size());
+
+ for (Map.Entry<RecordId, RecordType> entry : roots.entrySet()) {
+ int offset = entry.getKey().getOffset();
+ b.put((byte) entry.getValue().ordinal());
+ b.put((byte) (offset >> (8 + Segment.RECORD_ALIGN_BITS)));
+ b.put((byte) (offset >> Segment.RECORD_ALIGN_BITS));
+ }
+
+ p = b.position() - p;
+ int q = Segment.align(p);
+ for (int i = p; i < q; i++) {
+ b.put((byte) 0);
+ }
+
+ for (UUID refid : refids.keySet()) {
+ b.putLong(refid.getMostSignificantBits());
+ b.putLong(refid.getLeastSignificantBits());
+ }
+ }
+
public synchronized Segment getCurrentSegment(UUID id) {
if (equal(id, uuid)) {
if (currentSegment == null) {
- ByteBuffer b = ByteBuffer.allocate(16 * refids.size() +
length);
- for (UUID refid : refids.keySet()) {
- b.putLong(refid.getMostSignificantBits());
- b.putLong(refid.getLeastSignificantBits());
- }
+ int header = align(3 + roots.size() * 3) + 16 * refids.size();
+ ByteBuffer b = ByteBuffer.allocate(header + length);
+ writeSegmentHeader(b);
b.put(buffer, buffer.length - length, length);
b.rewind();
currentSegment = new Segment(store, uuid, b);
@@ -162,14 +186,11 @@ public class SegmentWriter {
public synchronized void flush() {
if (length > 0) {
- length += 16 * refids.size();
+ length += align(3 + roots.size() * 3) + refids.size() * 16;
ByteBuffer b = ByteBuffer.wrap(
- buffer, buffer.length - length, 16 * refids.size());
- for (UUID refid : refids.keySet()) {
- b.putLong(refid.getMostSignificantBits());
- b.putLong(refid.getLeastSignificantBits());
- }
+ buffer, buffer.length - length, length);
+ writeSegmentHeader(b);
store.writeSegment(uuid, buffer, buffer.length - length, length);
@@ -204,19 +225,16 @@ public class SegmentWriter {
rootIds.removeAll(ids);
int rootCount = rootIds.size() + 1;
- int fullSize = size + ids.size() * Segment.RECORD_ID_BYTES;
- int alignment = Segment.RECORD_ALIGN_BYTES - 1;
- int alignedSize = (fullSize + alignment) & ~alignment;
-
- int segmentSize =
- 3 + rootCount * 3 + refCount * 16 + alignedSize + length;
+ int recordSize = Segment.align(size + ids.size() *
Segment.RECORD_ID_BYTES);
+ int headerSize = Segment.align(3 + rootCount * 3);
+ int segmentSize = headerSize + refCount * 16 + recordSize + length;
if (segmentSize > buffer.length - 1
|| rootCount > 0xffff
|| refCount > Segment.SEGMENT_REFERENCE_LIMIT) {
flush();
}
- length += alignedSize;
+ length += recordSize;
position = buffer.length - length;
checkState(position >= 0);
@@ -247,7 +265,7 @@ public class SegmentWriter {
int offset = id.getOffset();
checkState(0 <= offset && offset < MAX_SEGMENT_SIZE);
- checkState((offset & (Segment.RECORD_ALIGN_BYTES - 1)) == 0);
+ checkState(offset == Segment.align(offset));
buffer[position++] = (byte) (offset >> (8 +
Segment.RECORD_ALIGN_BITS));
buffer[position++] = (byte) (offset >> Segment.RECORD_ALIGN_BITS);
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java?rev=1539759&r1=1539758&r2=1539759&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
Thu Nov 7 18:50:12 2013
@@ -40,29 +40,29 @@ public class SegmentSizeTest {
@Test
public void testNodeSize() {
NodeBuilder builder = EMPTY_NODE.builder();
- assertEquals(20, getSize(builder));
+ assertEquals(28, getSize(builder));
assertEquals(4, getAmortizedSize(builder));
builder = EMPTY_NODE.builder();
builder.setProperty("foo", "bar");
- assertEquals(24, getSize(builder));
+ assertEquals(32, getSize(builder));
assertEquals(8, getAmortizedSize(builder));
builder = EMPTY_NODE.builder();
builder.setProperty("foo", "bar");
builder.setProperty("baz", 123);
- assertEquals(40, getSize(builder));
+ assertEquals(48, getSize(builder));
assertEquals(12, getAmortizedSize(builder));
builder = EMPTY_NODE.builder();
builder.child("foo");
- assertEquals(40, getSize(builder));
+ assertEquals(48, getSize(builder));
assertEquals(12, getAmortizedSize(builder));
builder = EMPTY_NODE.builder();
builder.child("foo");
builder.child("bar");
- assertEquals(68, getSize(builder));
+ assertEquals(76, getSize(builder));
assertEquals(40, getAmortizedSize(builder));
}
@@ -106,7 +106,7 @@ public class SegmentSizeTest {
public void testAccessControlNodes() {
NodeBuilder builder = EMPTY_NODE.builder();
builder.setProperty("jcr:primaryType", "rep:ACL", Type.NAME);
- assertEquals(20, getSize(builder));
+ assertEquals(28, getSize(builder));
assertEquals(4, getAmortizedSize(builder));
NodeBuilder deny = builder.child("deny");
@@ -114,7 +114,7 @@ public class SegmentSizeTest {
deny.setProperty("rep:principalName", "everyone");
deny.setProperty(PropertyStates.createProperty(
"rep:privileges", ImmutableList.of("jcr:read"), Type.NAMES));
- assertEquals(144, getSize(builder));
+ assertEquals(152, getSize(builder));
assertEquals(28, getAmortizedSize(builder));
NodeBuilder allow = builder.child("allow");
@@ -122,7 +122,7 @@ public class SegmentSizeTest {
allow.setProperty("rep:principalName", "administrators");
allow.setProperty(PropertyStates.createProperty(
"rep:privileges", ImmutableList.of("jcr:all"), Type.NAMES));
- assertEquals(264, getSize(builder));
+ assertEquals(272, getSize(builder));
assertEquals(72, getAmortizedSize(builder));
NodeBuilder deny0 = builder.child("deny0");
@@ -131,7 +131,7 @@ public class SegmentSizeTest {
deny0.setProperty("rep:glob", "*/activities/*");
builder.setProperty(PropertyStates.createProperty(
"rep:privileges", ImmutableList.of("jcr:read"), Type.NAMES));
- assertEquals(356, getSize(builder));
+ assertEquals(364, getSize(builder));
assertEquals(108, getAmortizedSize(builder));
NodeBuilder allow0 = builder.child("allow0");
@@ -139,7 +139,7 @@ public class SegmentSizeTest {
allow0.setProperty("rep:principalName", "user-administrators");
allow0.setProperty(PropertyStates.createProperty(
"rep:privileges", ImmutableList.of("jcr:all"), Type.NAMES));
- assertEquals(412, getSize(builder));
+ assertEquals(420, getSize(builder));
assertEquals(136, getAmortizedSize(builder));
}
@@ -155,7 +155,7 @@ public class SegmentSizeTest {
SegmentNodeState state = writer.writeNode(builder.getNodeState());
Segment segment =
store.readSegment(state.getRecordId().getSegmentId());
- assertEquals(26744, Segment.WEIGHER.weigh(null, segment));
+ assertEquals(26752, Segment.WEIGHER.weigh(null, segment));
writer.flush(); // force flushing of the previous segment
@@ -163,7 +163,7 @@ public class SegmentSizeTest {
builder.child("child1000");
state = writer.writeNode(builder.getNodeState());
segment = store.readSegment(state.getRecordId().getSegmentId());
- assertEquals(128, Segment.WEIGHER.weigh(null, segment));
+ assertEquals(136, Segment.WEIGHER.weigh(null, segment));
}
private int getSize(NodeBuilder builder) {
@@ -187,7 +187,7 @@ public class SegmentSizeTest {
writer.writeNode(state);
id = writer.writeNode(state).getRecordId();
segment = store.readSegment(id.getSegmentId());
- return Segment.WEIGHER.weigh(null, segment) - base;
+ return Segment.WEIGHER.weigh(null, segment) - base - 4;
}
}