Author: jukka
Date: Sun Sep 29 03:08:48 2013
New Revision: 1527267
URL: http://svn.apache.org/r1527267
Log:
OAK-1031: SegmentMK: Fewer segment lookups
Cache map records and the string keys of map leaves
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.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/SegmentWriter.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java?rev=1527267&r1=1527266&r2=1527267&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java
Sun Sep 29 03:08:48 2013
@@ -34,6 +34,13 @@ class MapBranch extends MapRecord {
private final int bitmap;
+ MapBranch(Segment segment, int offset, int size, int level, int bitmap) {
+ super(segment, offset, size, level);
+ checkArgument(size > BUCKETS_PER_LEVEL);
+ checkArgument(level < MAX_NUMBER_OF_LEVELS);
+ this.bitmap = bitmap;
+ }
+
MapBranch(Segment segment, RecordId id, int size, int level, int bitmap) {
super(segment, id, size, level);
checkArgument(size > BUCKETS_PER_LEVEL);
@@ -70,7 +77,7 @@ class MapBranch extends MapRecord {
int bytes = 8;
int ids = bitCount(bitmap & (bit - 1));
RecordId id = segment.readRecordId(getOffset(bytes, ids));
- return MapRecord.readMap(segment, id).getEntry(key);
+ return segment.readMap(id).getEntry(key);
} else {
return null;
}
@@ -85,7 +92,7 @@ class MapBranch extends MapRecord {
@Override @Nullable
public Iterable<String> apply(@Nullable RecordId input) {
if (input != null) {
- return MapRecord.readMap(segment, input).getKeys();
+ return segment.readMap(input).getKeys();
} else {
return Collections.emptyList();
}
@@ -102,7 +109,7 @@ class MapBranch extends MapRecord {
@Override @Nullable
public Iterable<MapEntry> apply(@Nullable RecordId input) {
if (input != null) {
- return MapRecord.readMap(segment,
input).getEntries();
+ return segment.readMap(input).getEntries();
} else {
return Collections.emptyList();
}
@@ -130,7 +137,7 @@ class MapBranch extends MapRecord {
for (int i = 0; i < BUCKETS_PER_LEVEL; i++) {
if (afterBuckets[i] == null) {
if (beforeBuckets[i] != null) {
- MapRecord map = MapRecord.readMap(beforeSegment,
beforeBuckets[i]);
+ MapRecord map = beforeSegment.readMap(beforeBuckets[i]);
for (MapEntry entry : map.getEntries()) {
if (!diff.entryDeleted(entry.getName(),
entry.getValue())) {
return false;
@@ -138,15 +145,15 @@ class MapBranch extends MapRecord {
}
}
} else if (beforeBuckets[i] == null) {
- MapRecord map = MapRecord.readMap(afterSegment,
afterBuckets[i]);
+ MapRecord map = afterSegment.readMap(afterBuckets[i]);
for (MapEntry entry : map.getEntries()) {
if (!diff.entryAdded(entry.getName(), entry.getValue())) {
return false;
}
}
} else if (!afterBuckets[i].equals(beforeBuckets[i])) {
- MapRecord afterMap = MapRecord.readMap(afterSegment,
afterBuckets[i]);
- MapRecord beforeMap = MapRecord.readMap(beforeSegment,
beforeBuckets[i]);
+ MapRecord afterMap = afterSegment.readMap(afterBuckets[i]);
+ MapRecord beforeMap = beforeSegment.readMap(beforeBuckets[i]);
if (!afterMap.compare(beforeMap, diff)) {
return false;
}
@@ -163,8 +170,8 @@ class MapBranch extends MapRecord {
int ids = 0;
for (int i = 0; i < BUCKETS_PER_LEVEL; i++) {
if ((bitmap & (1 << i)) != 0) {
- MapRecord bucket = MapRecord.readMap(
- segment, segment.readRecordId(getOffset(bytes,
ids++)));
+ MapRecord bucket = segment.readMap(
+ segment.readRecordId(getOffset(bytes, ids++)));
if (!bucket.compareAgainstEmptyMap(diff)) {
return false;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java?rev=1527267&r1=1527266&r2=1527267&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java
Sun Sep 29 03:08:48 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
org.apache.jackrabbit.oak.plugins.segment.Segment.RECORD_ID_BYTES;
import java.util.Iterator;
import java.util.Map;
@@ -28,10 +27,20 @@ import com.google.common.collect.Maps;
class MapLeaf extends MapRecord {
+ private final String[] keys;
+
+ MapLeaf(Segment segment, int offset, int size, int level) {
+ super(segment, offset, size, level);
+ checkArgument(size != 0 || level == 0);
+ checkArgument(size <= BUCKETS_PER_LEVEL || level ==
MAX_NUMBER_OF_LEVELS);
+ this.keys = new String[size];
+ }
+
MapLeaf(Segment segment, RecordId id, int size, int level) {
super(segment, id, size, level);
checkArgument(size != 0 || level == 0);
checkArgument(size <= BUCKETS_PER_LEVEL || level ==
MAX_NUMBER_OF_LEVELS);
+ this.keys = new String[size];
}
Map<String, MapEntry> getMapEntries() {
@@ -50,7 +59,7 @@ class MapLeaf extends MapRecord {
Map<String, MapEntry> entries = Maps.newHashMapWithExpectedSize(size);
for (int i = 0; i < size; i++) {
- String name = segment.readString(keys[i]);
+ String name = getKey(segment, i, keys[i]);
entries.put(name, new MapEntry(segment, name, keys[i], values[i]));
}
return entries;
@@ -86,7 +95,6 @@ class MapLeaf extends MapRecord {
public Iterator<String> iterator() {
return getKeyIterator();
}
-
};
}
@@ -159,12 +167,10 @@ class MapLeaf extends MapRecord {
public boolean compareAgainstEmptyMap(MapDiff diff) {
Segment segment = getSegment();
- int keyOffset = getOffset() + 4 + size * 4;
- int valueOffset = keyOffset + size * RECORD_ID_BYTES;
for (int i = 0; i < size; i++) {
- RecordId key = segment.readRecordId(keyOffset + i *
RECORD_ID_BYTES);
- RecordId value = segment.readRecordId(valueOffset + i *
RECORD_ID_BYTES);
- if (!diff.entryAdded(segment.readString(key), value)) {
+ RecordId key = segment.readRecordId(getOffset(4 + size * 4, i));
+ RecordId value = segment.readRecordId(getOffset(4 + size * 4, size
+ i));
+ if (!diff.entryAdded(getKey(segment, i, key), value)) {
return false;
}
}
@@ -202,16 +208,25 @@ class MapLeaf extends MapRecord {
return checkNotNull(segment).readInt(getOffset() + 4 + index * 4);
}
- private String getKey(Segment segment, int index) {
+ private synchronized String getKey(Segment segment, int index) {
checkNotNull(segment);
- int offset = getOffset() + 4 + size * 4 + index * RECORD_ID_BYTES;
- return segment.readString(segment.readRecordId(offset));
+ if (keys[index] == null) {
+ int offset = getOffset(4 + size * 4, index);
+ keys[index] = segment.readString(segment.readRecordId(offset));
+ }
+ return keys[index];
+ }
+
+ private synchronized String getKey(Segment segment, int index, RecordId
id) {
+ checkNotNull(segment);
+ if (keys[index] == null) {
+ keys[index] = segment.readString(id);
+ }
+ return keys[index];
}
private RecordId getValue(Segment segment, int index) {
- int offset = getOffset()
- + 4 + size * 4 + size * RECORD_ID_BYTES
- + index * RECORD_ID_BYTES;
+ int offset = getOffset(4 + size * 4, size + index);
return checkNotNull(segment).readRecordId(offset);
}
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=1527267&r1=1527266&r2=1527267&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
Sun Sep 29 03:08:48 2013
@@ -17,14 +17,12 @@
package org.apache.jackrabbit.oak.plugins.segment;
import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkPositionIndex;
import static com.google.common.collect.Sets.newHashSet;
import static java.lang.Integer.highestOneBit;
import static java.lang.Integer.numberOfTrailingZeros;
import java.util.Set;
-import java.util.UUID;
abstract class MapRecord extends Record {
@@ -60,24 +58,16 @@ abstract class MapRecord extends Record
*/
protected static final int MAX_SIZE = (1 << SIZE_BITS) - 1; // ~268e6
- static MapRecord readMap(Segment segment, RecordId id) {
- segment = checkNotNull(segment).getSegment(checkNotNull(id));
- int offset = id.getOffset();
- int head = segment.readInt(offset);
- int level = head >>> SIZE_BITS;
- int size = head & ((1 << SIZE_BITS) - 1);
- if (size > BUCKETS_PER_LEVEL && level < MAX_NUMBER_OF_LEVELS) {
- int bitmap = segment.readInt(offset + 4);
- return new MapBranch(segment, id, size, level, bitmap);
- } else {
- return new MapLeaf(segment, id, size, level);
- }
- }
-
protected final int size;
protected final int level;
+ protected MapRecord(Segment segment, int offset, int size, int level) {
+ super(segment, offset);
+ this.size = checkElementIndex(size, MAX_SIZE);
+ this.level = checkPositionIndex(level, MAX_NUMBER_OF_LEVELS);
+ }
+
protected MapRecord(Segment segment, RecordId id, int size, int level) {
super(segment, id);
this.size = checkElementIndex(size, MAX_SIZE);
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=1527267&r1=1527266&r2=1527267&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
Sun Sep 29 03:08:48 2013
@@ -73,6 +73,12 @@ class Record {
this.offset = id.getOffset();
}
+ protected Record(@Nonnull Segment segment, int offset) {
+ this.segment = checkNotNull(segment);
+ this.uuid = segment.getSegmentId();
+ this.offset = offset;
+ }
+
// TODO: remove this ugly hack
protected Record(SegmentStore store, RecordId id) {
this(new Segment(
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=1527267&r1=1527266&r2=1527267&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
Sun Sep 29 03:08:48 2013
@@ -101,6 +101,8 @@ public class Segment {
private final OffsetCache<Template> templates;
+ private final OffsetCache<MapRecord> maps;
+
public Segment(
SegmentStore store, UUID uuid, ByteBuffer data, List<UUID> uuids) {
this.store = checkNotNull(store);
@@ -119,6 +121,12 @@ public class Segment {
return loadTemplate(offset);
}
};
+ this.maps = new OffsetCache<MapRecord>() {
+ @Override
+ protected MapRecord load(int offset) {
+ return loadMap(offset);
+ }
+ };
}
/**
@@ -253,6 +261,27 @@ public class Segment {
}
}
+ MapRecord readMap(RecordId id) {
+ return getSegment(id).readMap(id.getOffset());
+ }
+
+ MapRecord readMap(int offset) {
+ return maps.get(offset);
+ }
+
+ private MapRecord loadMap(int offset) {
+ int head = readInt(offset);
+ int level = head >>> MapRecord.SIZE_BITS;
+ int size = head & ((1 << MapRecord.SIZE_BITS) - 1);
+ if (size > MapRecord.BUCKETS_PER_LEVEL
+ && level < MapRecord.MAX_NUMBER_OF_LEVELS) {
+ int bitmap = readInt(offset + 4);
+ return new MapBranch(this, offset, size, level, bitmap);
+ } else {
+ return new MapLeaf(this, offset, size, level);
+ }
+ }
+
Template readTemplate(RecordId id) {
return getSegment(id).readTemplate(id.getOffset());
}
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=1527267&r1=1527266&r2=1527267&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
Sun Sep 29 03:08:48 2013
@@ -288,7 +288,7 @@ public class SegmentWriter {
if (entries == null || entries.isEmpty()) {
if (baseId != null) {
- return MapRecord.readMap(dummySegment, baseId);
+ return dummySegment.readMap(baseId);
} else if (level == 0) {
synchronized (this) {
RecordId id = prepare(4);
@@ -300,7 +300,7 @@ public class SegmentWriter {
}
} else if (baseId != null) {
// FIXME: messy code with lots of duplication
- MapRecord base = MapRecord.readMap(dummySegment, baseId);
+ MapRecord base = dummySegment.readMap(baseId);
if (base instanceof MapLeaf) {
Map<String, MapEntry> map = ((MapLeaf) base).getMapEntries();
for (MapEntry entry : entries) {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java?rev=1527267&r1=1527266&r2=1527267&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/Template.java
Sun Sep 29 03:08:48 2013
@@ -279,7 +279,7 @@ public class Template {
segment = segment.getSegment(recordId);
int offset = recordId.getOffset() + RECORD_ID_BYTES;
RecordId childNodesId = segment.readRecordId(offset);
- return MapRecord.readMap(segment, childNodesId);
+ return segment.readMap(childNodesId);
}
public boolean hasChildNode(
@@ -562,7 +562,7 @@ public class Template {
if (childName == MANY_CHILD_NODES) {
RecordId childNodesId = segment.readRecordId(offset);
- MapRecord children = MapRecord.readMap(segment, childNodesId);
+ MapRecord children = segment.readMap(childNodesId);
final Segment s = segment;
children.compareAgainstEmptyMap(new MapDiff() {
@Override