You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2013/10/25 16:11:58 UTC
svn commit: r1535743 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/segment/
test/java/org/apache/jackrabbit/oak/plugins/segment/
Author: jukka
Date: Fri Oct 25 14:11:58 2013
New Revision: 1535743
URL: http://svn.apache.org/r1535743
Log:
OAK-593: Segment-based MK
Simplify segment size and record position handling
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/AbstractStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Segment.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/AbstractStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/AbstractStore.java?rev=1535743&r1=1535742&r2=1535743&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/AbstractStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/AbstractStore.java Fri Oct 25 14:11:58 2013
@@ -25,7 +25,6 @@ import java.util.concurrent.Callable;
import org.apache.jackrabbit.oak.cache.CacheLIRS;
import com.google.common.cache.Cache;
-import com.google.common.cache.Weigher;
public abstract class AbstractStore implements SegmentStore {
@@ -43,12 +42,7 @@ public abstract class AbstractStore impl
protected AbstractStore(int cacheSize) {
this.segments = CacheLIRS.newBuilder()
- .weigher(new Weigher<UUID, Segment>() {
- @Override
- public int weigh(UUID key, Segment value) {
- return value.size();
- }
- })
+ .weigher(Segment.WEIGHER)
.maximumWeight(cacheSize)
.build();
}
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=1535743&r1=1535742&r2=1535743&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 Fri Oct 25 14:11:58 2013
@@ -1,360 +1,354 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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.checkPositionIndexes;
-import static org.apache.jackrabbit.oak.plugins.segment.SegmentWriter.BLOCK_SIZE;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
-
-import com.google.common.base.Charsets;
-import com.google.common.cache.Weigher;
-
-public class Segment {
-
- /**
- * Number of bytes used for storing a record identifier. One byte
- * is used for identifying the segment and two for the record offset
- * within that segment.
- */
- static final int RECORD_ID_BYTES = 1 + 2;
-
- /**
- * The limit on segment references within one segment. Since record
- * identifiers use one byte to indicate the referenced segment, a single
- * segment can hold references to up to 256 segments.
- */
- static final int SEGMENT_REFERENCE_LIMIT = 1 << 8; // 256
-
- /**
- * 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
-
- /**
- * Maximum segment size. Record identifiers are stored as three-byte
- * sequences with the first byte indicating the segment and the next
- * two the offset within that segment. Since all records are aligned
- * at four-byte boundaries, the two bytes can address up to 256kB of
- * record data.
- */
- static final int MAX_SEGMENT_SIZE = 1 << (16 + RECORD_ALIGN_BITS); // 256kB
-
- /**
- * The size limit for small values. The variable length of small values
- * is encoded as a single byte with the high bit as zero, which gives us
- * seven bits for encoding the length of the value.
- */
- static final int SMALL_LIMIT = 1 << 7;
-
- /**
- * The size limit for medium values. The variable length of medium values
- * is encoded as two bytes with the highest bits of the first byte set to
- * one and zero, which gives us 14 bits for encoding the length of the
- * value. And since small values are never stored as medium ones, we can
- * extend the size range to cover that many longer values.
- */
- static final int MEDIUM_LIMIT = (1 << (16 - 2)) + SMALL_LIMIT;
-
- static final Weigher<UUID, Segment> WEIGHER =
- new Weigher<UUID, Segment>() {
- @Override
- public int weigh(UUID key, Segment value) {
- return value.size();
- }
- };
-
- final SegmentStore store; // TODO: should be private
-
- private final UUID uuid;
-
- private final ByteBuffer data;
-
- private final List<UUID> uuids;
-
- public Segment(
- SegmentStore store, UUID uuid, ByteBuffer data, List<UUID> uuids) {
- this.store = checkNotNull(store);
- this.uuid = checkNotNull(uuid);
- this.data = checkNotNull(data);
- this.uuids = checkNotNull(uuids);
- }
-
- /**
- * Maps the given record offset to the respective position within the
- * internal {@link #data} array. The validity of a record with the given
- * length at the given offset is also verified.
- *
- * @param offset record offset
- * @param length record length
- * @return position within the data array
- */
- private int pos(int offset, int length) {
- int pos = offset - (MAX_SEGMENT_SIZE - size());
- checkPositionIndexes(pos, pos + length, size());
- return data.position() + pos;
- }
-
- public UUID getSegmentId() {
- return uuid;
- }
-
- public ByteBuffer getData() {
- return data;
- }
-
- public int size() {
- return data.remaining();
- }
-
- byte readByte(int offset) {
- return data.get(pos(offset, 1));
- }
-
- /**
- * Returns the identified segment.
- *
- * @param uuid segment identifier
- * @return identified segment
- */
- Segment getSegment(UUID uuid) {
- if (equal(uuid, this.uuid)) {
- return this; // optimization for the common case (OAK-1031)
- } else {
- return store.readSegment(uuid);
- }
- }
-
- /**
- * Returns the segment that contains the identified record.
- *
- * @param id record identifier
- * @return segment that contains the identified record
- */
- Segment getSegment(RecordId id) {
- return getSegment(checkNotNull(id).getSegmentId());
- }
-
-
- /**
- * Reads the given number of bytes starting from the given position
- * in this segment.
- *
- * @param position position within segment
- * @param buffer target buffer
- * @param offset offset within target buffer
- * @param length number of bytes to read
- */
- void readBytes(int position, byte[] buffer, int offset, int length) {
- checkNotNull(buffer);
- checkPositionIndexes(offset, offset + length, buffer.length);
- ByteBuffer d = data.duplicate();
- d.position(pos(position, length));
- d.get(buffer, offset, length);
- }
-
- RecordId readRecordId(int offset) {
- int pos = pos(offset, RECORD_ID_BYTES);
- return internalReadRecordId(pos);
- }
-
- private RecordId internalReadRecordId(int pos) {
- return new RecordId(
- uuids.get(data.get(pos) & 0xff),
- (data.get(pos + 1) & 0xff) << (8 + Segment.RECORD_ALIGN_BITS)
- | (data.get(pos + 2) & 0xff) << Segment.RECORD_ALIGN_BITS);
- }
-
- int readInt(int offset) {
- int pos = pos(offset, 4);
- return (data.get(pos) & 0xff) << 24
- | (data.get(pos + 1) & 0xff) << 16
- | (data.get(pos + 2) & 0xff) << 8
- | (data.get(pos + 3) & 0xff);
- }
-
- String readString(final RecordId id) {
- return store.getRecord(id, new Callable<String>() {
- @Override
- public String call() {
- return getSegment(id).readString(id.getOffset());
- }
- });
- }
-
- String readString(int offset) {
- int pos = pos(offset, 1);
- long length = internalReadLength(pos);
- if (length < SMALL_LIMIT) {
- byte[] bytes = new byte[(int) length];
- ByteBuffer buffer = data.duplicate();
- buffer.position(pos + 1);
- buffer.get(bytes);
- return new String(bytes, Charsets.UTF_8);
- } else if (length < MEDIUM_LIMIT) {
- byte[] bytes = new byte[(int) length];
- ByteBuffer buffer = data.duplicate();
- buffer.position(pos + 2);
- buffer.get(bytes);
- return new String(bytes, Charsets.UTF_8);
- } else if (length < Integer.MAX_VALUE) {
- int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
- ListRecord list =
- new ListRecord(this, internalReadRecordId(pos + 8), size);
- SegmentStream stream = new SegmentStream(
- store, new RecordId(uuid, offset), list, length);
- try {
- return stream.getString();
- } finally {
- stream.close();
- }
- } else {
- throw new IllegalStateException("String is too long: " + length);
- }
- }
-
- MapRecord readMap(RecordId id) {
- return new MapRecord(this, id);
- }
-
- Template readTemplate(final RecordId id) {
- return store.getRecord(id, new Callable<Template>() {
- @Override
- public Template call() {
- return getSegment(id).readTemplate(id.getOffset());
- }
- });
- }
-
- Template readTemplate(int offset) {
- int head = readInt(offset);
- boolean hasPrimaryType = (head & (1 << 31)) != 0;
- boolean hasMixinTypes = (head & (1 << 30)) != 0;
- boolean zeroChildNodes = (head & (1 << 29)) != 0;
- boolean manyChildNodes = (head & (1 << 28)) != 0;
- int mixinCount = (head >> 18) & ((1 << 10) - 1);
- int propertyCount = head & ((1 << 18) - 1);
- offset += 4;
-
- PropertyState primaryType = null;
- if (hasPrimaryType) {
- RecordId primaryId = readRecordId(offset);
- primaryType = PropertyStates.createProperty(
- "jcr:primaryType", readString(primaryId), Type.NAME);
- offset += Segment.RECORD_ID_BYTES;
- }
-
- PropertyState mixinTypes = null;
- if (hasMixinTypes) {
- String[] mixins = new String[mixinCount];
- for (int i = 0; i < mixins.length; i++) {
- RecordId mixinId = readRecordId(offset);
- mixins[i] = readString(mixinId);
- offset += Segment.RECORD_ID_BYTES;
- }
- mixinTypes = PropertyStates.createProperty(
- "jcr:mixinTypes", Arrays.asList(mixins), Type.NAMES);
- }
-
- String childName = Template.ZERO_CHILD_NODES;
- if (manyChildNodes) {
- childName = Template.MANY_CHILD_NODES;
- } else if (!zeroChildNodes) {
- RecordId childNameId = readRecordId(offset);
- childName = readString(childNameId);
- offset += Segment.RECORD_ID_BYTES;
- }
-
- PropertyTemplate[] properties =
- new PropertyTemplate[propertyCount];
- for (int i = 0; i < properties.length; i++) {
- RecordId propertyNameId = readRecordId(offset);
- offset += Segment.RECORD_ID_BYTES;
- byte type = readByte(offset++);
- properties[i] = new PropertyTemplate(
- i, readString(propertyNameId),
- Type.fromTag(Math.abs(type), type < 0));
- }
-
- return new Template(
- primaryType, mixinTypes, properties, childName);
- }
-
- long readLength(RecordId id) {
- return getSegment(id).readLength(id.getOffset());
- }
-
- long readLength(int offset) {
- return internalReadLength(pos(offset, 1));
- }
-
- private long internalReadLength(int pos) {
- int length = data.get(pos++) & 0xff;
- if ((length & 0x80) == 0) {
- return length;
- } else if ((length & 0x40) == 0) {
- return ((length & 0x3f) << 8
- | data.get(pos++) & 0xff)
- + SMALL_LIMIT;
- } else {
- return (((long) length & 0x3f) << 56
- | ((long) (data.get(pos++) & 0xff)) << 48
- | ((long) (data.get(pos++) & 0xff)) << 40
- | ((long) (data.get(pos++) & 0xff)) << 32
- | ((long) (data.get(pos++) & 0xff)) << 24
- | ((long) (data.get(pos++) & 0xff)) << 16
- | ((long) (data.get(pos++) & 0xff)) << 8
- | ((long) (data.get(pos++) & 0xff)))
- + MEDIUM_LIMIT;
- }
- }
-
- SegmentStream readStream(int offset) {
- RecordId id = new RecordId(uuid, offset);
- int pos = pos(offset, 1);
- long length = internalReadLength(pos);
- if (length < Segment.MEDIUM_LIMIT) {
- byte[] inline = new byte[(int) length];
- ByteBuffer buffer = data.duplicate();
- if (length < Segment.SMALL_LIMIT) {
- buffer.position(pos + 1);
- } else {
- buffer.position(pos + 2);
- }
- buffer.get(inline);
- return new SegmentStream(id, inline);
- } else {
- int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
- ListRecord list =
- new ListRecord(this, internalReadRecordId(pos + 8), size);
- return new SegmentStream(store, id, list, length);
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.checkPositionIndexes;
+import static com.google.common.base.Preconditions.checkState;
+import static org.apache.jackrabbit.oak.plugins.segment.SegmentWriter.BLOCK_SIZE;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+
+import com.google.common.base.Charsets;
+import com.google.common.cache.Weigher;
+
+public class Segment {
+
+ /**
+ * Number of bytes used for storing a record identifier. One byte
+ * is used for identifying the segment and two for the record offset
+ * within that segment.
+ */
+ static final int RECORD_ID_BYTES = 1 + 2;
+
+ /**
+ * The limit on segment references within one segment. Since record
+ * identifiers use one byte to indicate the referenced segment, a single
+ * segment can hold references to up to 256 segments.
+ */
+ static final int SEGMENT_REFERENCE_LIMIT = 1 << 8; // 256
+
+ /**
+ * 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
+
+ /**
+ * Maximum segment size. Record identifiers are stored as three-byte
+ * sequences with the first byte indicating the segment and the next
+ * two the offset within that segment. Since all records are aligned
+ * at four-byte boundaries, the two bytes can address up to 256kB of
+ * record data.
+ */
+ static final int MAX_SEGMENT_SIZE = 1 << (16 + RECORD_ALIGN_BITS); // 256kB
+
+ /**
+ * The size limit for small values. The variable length of small values
+ * is encoded as a single byte with the high bit as zero, which gives us
+ * seven bits for encoding the length of the value.
+ */
+ static final int SMALL_LIMIT = 1 << 7;
+
+ /**
+ * The size limit for medium values. The variable length of medium values
+ * is encoded as two bytes with the highest bits of the first byte set to
+ * one and zero, which gives us 14 bits for encoding the length of the
+ * value. And since small values are never stored as medium ones, we can
+ * extend the size range to cover that many longer values.
+ */
+ static final int MEDIUM_LIMIT = (1 << (16 - 2)) + SMALL_LIMIT;
+
+ static final Weigher<UUID, Segment> WEIGHER =
+ new Weigher<UUID, Segment>() {
+ @Override
+ public int weigh(UUID key, Segment value) {
+ return value.data.remaining();
+ }
+ };
+
+ final SegmentStore store; // TODO: should be private
+
+ private final UUID uuid;
+
+ private final ByteBuffer data;
+
+ private final List<UUID> uuids;
+
+ public Segment(
+ SegmentStore store, UUID uuid, ByteBuffer data, List<UUID> uuids) {
+ this.store = checkNotNull(store);
+ this.uuid = checkNotNull(uuid);
+ this.data = checkNotNull(data);
+ this.uuids = checkNotNull(uuids);
+ }
+
+ /**
+ * Maps the given record offset to the respective position within the
+ * internal {@link #data} array. The validity of a record with the given
+ * length at the given offset is also verified.
+ *
+ * @param offset record offset
+ * @param length record length
+ * @return position within the data array
+ */
+ private int pos(int offset, int length) {
+ checkPositionIndexes(offset, offset + length, MAX_SEGMENT_SIZE);
+ int pos = data.limit() - MAX_SEGMENT_SIZE + offset;
+ checkState(pos >= data.position());
+ return pos;
+ }
+
+ public UUID getSegmentId() {
+ return uuid;
+ }
+
+ byte readByte(int offset) {
+ return data.get(pos(offset, 1));
+ }
+
+ /**
+ * Returns the identified segment.
+ *
+ * @param uuid segment identifier
+ * @return identified segment
+ */
+ Segment getSegment(UUID uuid) {
+ if (equal(uuid, this.uuid)) {
+ return this; // optimization for the common case (OAK-1031)
+ } else {
+ return store.readSegment(uuid);
+ }
+ }
+
+ /**
+ * Returns the segment that contains the identified record.
+ *
+ * @param id record identifier
+ * @return segment that contains the identified record
+ */
+ Segment getSegment(RecordId id) {
+ return getSegment(checkNotNull(id).getSegmentId());
+ }
+
+
+ /**
+ * Reads the given number of bytes starting from the given position
+ * in this segment.
+ *
+ * @param position position within segment
+ * @param buffer target buffer
+ * @param offset offset within target buffer
+ * @param length number of bytes to read
+ */
+ void readBytes(int position, byte[] buffer, int offset, int length) {
+ checkNotNull(buffer);
+ checkPositionIndexes(offset, offset + length, buffer.length);
+ ByteBuffer d = data.duplicate();
+ d.position(pos(position, length));
+ d.get(buffer, offset, length);
+ }
+
+ RecordId readRecordId(int offset) {
+ int pos = pos(offset, RECORD_ID_BYTES);
+ return internalReadRecordId(pos);
+ }
+
+ private RecordId internalReadRecordId(int pos) {
+ return new RecordId(
+ uuids.get(data.get(pos) & 0xff),
+ (data.get(pos + 1) & 0xff) << (8 + Segment.RECORD_ALIGN_BITS)
+ | (data.get(pos + 2) & 0xff) << Segment.RECORD_ALIGN_BITS);
+ }
+
+ int readInt(int offset) {
+ int pos = pos(offset, 4);
+ return (data.get(pos) & 0xff) << 24
+ | (data.get(pos + 1) & 0xff) << 16
+ | (data.get(pos + 2) & 0xff) << 8
+ | (data.get(pos + 3) & 0xff);
+ }
+
+ String readString(final RecordId id) {
+ return store.getRecord(id, new Callable<String>() {
+ @Override
+ public String call() {
+ return getSegment(id).readString(id.getOffset());
+ }
+ });
+ }
+
+ String readString(int offset) {
+ int pos = pos(offset, 1);
+ long length = internalReadLength(pos);
+ if (length < SMALL_LIMIT) {
+ byte[] bytes = new byte[(int) length];
+ ByteBuffer buffer = data.duplicate();
+ buffer.position(pos + 1);
+ buffer.get(bytes);
+ return new String(bytes, Charsets.UTF_8);
+ } else if (length < MEDIUM_LIMIT) {
+ byte[] bytes = new byte[(int) length];
+ ByteBuffer buffer = data.duplicate();
+ buffer.position(pos + 2);
+ buffer.get(bytes);
+ return new String(bytes, Charsets.UTF_8);
+ } else if (length < Integer.MAX_VALUE) {
+ int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
+ ListRecord list =
+ new ListRecord(this, internalReadRecordId(pos + 8), size);
+ SegmentStream stream = new SegmentStream(
+ store, new RecordId(uuid, offset), list, length);
+ try {
+ return stream.getString();
+ } finally {
+ stream.close();
+ }
+ } else {
+ throw new IllegalStateException("String is too long: " + length);
+ }
+ }
+
+ MapRecord readMap(RecordId id) {
+ return new MapRecord(this, id);
+ }
+
+ Template readTemplate(final RecordId id) {
+ return store.getRecord(id, new Callable<Template>() {
+ @Override
+ public Template call() {
+ return getSegment(id).readTemplate(id.getOffset());
+ }
+ });
+ }
+
+ Template readTemplate(int offset) {
+ int head = readInt(offset);
+ boolean hasPrimaryType = (head & (1 << 31)) != 0;
+ boolean hasMixinTypes = (head & (1 << 30)) != 0;
+ boolean zeroChildNodes = (head & (1 << 29)) != 0;
+ boolean manyChildNodes = (head & (1 << 28)) != 0;
+ int mixinCount = (head >> 18) & ((1 << 10) - 1);
+ int propertyCount = head & ((1 << 18) - 1);
+ offset += 4;
+
+ PropertyState primaryType = null;
+ if (hasPrimaryType) {
+ RecordId primaryId = readRecordId(offset);
+ primaryType = PropertyStates.createProperty(
+ "jcr:primaryType", readString(primaryId), Type.NAME);
+ offset += Segment.RECORD_ID_BYTES;
+ }
+
+ PropertyState mixinTypes = null;
+ if (hasMixinTypes) {
+ String[] mixins = new String[mixinCount];
+ for (int i = 0; i < mixins.length; i++) {
+ RecordId mixinId = readRecordId(offset);
+ mixins[i] = readString(mixinId);
+ offset += Segment.RECORD_ID_BYTES;
+ }
+ mixinTypes = PropertyStates.createProperty(
+ "jcr:mixinTypes", Arrays.asList(mixins), Type.NAMES);
+ }
+
+ String childName = Template.ZERO_CHILD_NODES;
+ if (manyChildNodes) {
+ childName = Template.MANY_CHILD_NODES;
+ } else if (!zeroChildNodes) {
+ RecordId childNameId = readRecordId(offset);
+ childName = readString(childNameId);
+ offset += Segment.RECORD_ID_BYTES;
+ }
+
+ PropertyTemplate[] properties =
+ new PropertyTemplate[propertyCount];
+ for (int i = 0; i < properties.length; i++) {
+ RecordId propertyNameId = readRecordId(offset);
+ offset += Segment.RECORD_ID_BYTES;
+ byte type = readByte(offset++);
+ properties[i] = new PropertyTemplate(
+ i, readString(propertyNameId),
+ Type.fromTag(Math.abs(type), type < 0));
+ }
+
+ return new Template(
+ primaryType, mixinTypes, properties, childName);
+ }
+
+ long readLength(RecordId id) {
+ return getSegment(id).readLength(id.getOffset());
+ }
+
+ long readLength(int offset) {
+ return internalReadLength(pos(offset, 1));
+ }
+
+ private long internalReadLength(int pos) {
+ int length = data.get(pos++) & 0xff;
+ if ((length & 0x80) == 0) {
+ return length;
+ } else if ((length & 0x40) == 0) {
+ return ((length & 0x3f) << 8
+ | data.get(pos++) & 0xff)
+ + SMALL_LIMIT;
+ } else {
+ return (((long) length & 0x3f) << 56
+ | ((long) (data.get(pos++) & 0xff)) << 48
+ | ((long) (data.get(pos++) & 0xff)) << 40
+ | ((long) (data.get(pos++) & 0xff)) << 32
+ | ((long) (data.get(pos++) & 0xff)) << 24
+ | ((long) (data.get(pos++) & 0xff)) << 16
+ | ((long) (data.get(pos++) & 0xff)) << 8
+ | ((long) (data.get(pos++) & 0xff)))
+ + MEDIUM_LIMIT;
+ }
+ }
+
+ SegmentStream readStream(int offset) {
+ RecordId id = new RecordId(uuid, offset);
+ int pos = pos(offset, 1);
+ long length = internalReadLength(pos);
+ if (length < Segment.MEDIUM_LIMIT) {
+ byte[] inline = new byte[(int) length];
+ ByteBuffer buffer = data.duplicate();
+ if (length < Segment.SMALL_LIMIT) {
+ buffer.position(pos + 1);
+ } else {
+ buffer.position(pos + 2);
+ }
+ buffer.get(inline);
+ return new SegmentStream(id, inline);
+ } else {
+ int size = (int) ((length + BLOCK_SIZE - 1) / BLOCK_SIZE);
+ ListRecord list =
+ new ListRecord(this, internalReadRecordId(pos + 8), size);
+ return new SegmentStream(store, id, list, length);
+ }
+ }
+
+}
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=1535743&r1=1535742&r2=1535743&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 Fri Oct 25 14:11:58 2013
@@ -155,7 +155,7 @@ public class SegmentSizeTest {
SegmentNodeState state = writer.writeNode(builder.getNodeState());
Segment segment = store.readSegment(state.getRecordId().getSegmentId());
- assertEquals(26728, segment.size());
+ assertEquals(26728, 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(96, segment.size());
+ assertEquals(96, Segment.WEIGHER.weigh(null, segment));
}
private int getSize(NodeBuilder builder) {
@@ -171,7 +171,7 @@ public class SegmentSizeTest {
SegmentWriter writer = store.getWriter();
RecordId id = writer.writeNode(builder.getNodeState()).getRecordId();
Segment segment = store.readSegment(id.getSegmentId());
- return segment.size();
+ return Segment.WEIGHER.weigh(null, segment);
}
private int getAmortizedSize(NodeBuilder builder) {
@@ -179,14 +179,15 @@ public class SegmentSizeTest {
SegmentWriter writer = store.getWriter();
NodeState state = builder.getNodeState();
RecordId id = writer.writeNode(state).getRecordId();
- int base = store.readSegment(id.getSegmentId()).size();
+ Segment segment = store.readSegment(id.getSegmentId());
+ int base = Segment.WEIGHER.weigh(null, segment);
store = new MemoryStore(); // avoid cross-segment caching
writer = store.getWriter();
writer.writeNode(state);
id = writer.writeNode(state).getRecordId();
- Segment segment = store.readSegment(id.getSegmentId());
- return segment.size() - base;
+ segment = store.readSegment(id.getSegmentId());
+ return Segment.WEIGHER.weigh(null, segment) - base;
}
}