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/02/22 13:23:15 UTC
svn commit: r1449014 - 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 Feb 22 12:23:14 2013
New Revision: 1449014
URL: http://svn.apache.org/r1449014
Log:
OAK-632: SegmentMK: Efficient updates of flat nodes
Some initial cleanup and optimization of the HAMT code
Added:
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
Modified:
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/MemoryStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MongoStore.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/SegmentReader.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
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentSizeTest.java
Added: 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=1449014&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapBranch.java Fri Feb 22 12:23:14 2013
@@ -0,0 +1,100 @@
+/*
+ * 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.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
+import static java.lang.Integer.bitCount;
+import static org.apache.jackrabbit.oak.plugins.segment.Segment.RECORD_ID_BYTES;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+class MapBranch extends MapRecord {
+
+ private final int bitmap;
+
+ MapBranch(SegmentStore store, RecordId id, int size, int level, int bitmap) {
+ super(store, id, size, level);
+ checkArgument(size > BUCKETS_PER_LEVEL);
+ checkArgument(level < MAX_NUMBER_OF_LEVELS);
+ this.bitmap = bitmap;
+ }
+
+ @Override
+ RecordId getEntry(String key) {
+ checkNotNull(key);
+
+ int mask = BUCKETS_PER_LEVEL - 1;
+ int shift = level * LEVEL_BITS;
+ int index = (key.hashCode() >> shift) & mask;
+
+ int bit = 1 << index;
+ if ((bitmap & bit) != 0) {
+ int offset = getOffset()
+ + 8 + bitCount(bitmap & (bit - 1)) * RECORD_ID_BYTES;
+ RecordId id = getSegment().readRecordId(offset);
+ return MapRecord.readMap(store, id).getEntry(key);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ Iterable<String> getKeys() {
+ return concat(transform(
+ getBuckets(),
+ new Function<RecordId, Iterable<String>>() {
+ @Override @Nullable
+ public Iterable<String> apply(@Nullable RecordId input) {
+ return MapRecord.readMap(store, input).getKeys();
+ }
+ }));
+ }
+
+ @Override
+ Iterable<Entry> getEntries() {
+ return concat(transform(
+ getBuckets(),
+ new Function<RecordId, Iterable<Entry>>() {
+ @Override @Nullable
+ public Iterable<Entry> apply(@Nullable RecordId input) {
+ return MapRecord.readMap(store, input).getEntries();
+ }
+ }));
+ }
+
+ private Iterable<RecordId> getBuckets() {
+ int n = Integer.bitCount(bitmap);
+ int p = getOffset() + 8;
+ int q = p + n * RECORD_ID_BYTES;
+ Segment segment = getSegment();
+
+ List<RecordId> buckets = Lists.newArrayListWithCapacity(n);
+ for (int o = p; o < q; o += RECORD_ID_BYTES) {
+ buckets.add(segment.readRecordId(o));
+ }
+ return buckets;
+ }
+
+}
Added: 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=1449014&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapLeaf.java Fri Feb 22 12:23:14 2013
@@ -0,0 +1,163 @@
+/*
+ * 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.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.NoSuchElementException;
+
+class MapLeaf extends MapRecord {
+
+ MapLeaf(SegmentStore store, RecordId id, int size, int level) {
+ super(store, id, size, level);
+ System.out.println(size + " " + level);
+ checkArgument(size != 0 || level == 0);
+ checkArgument(size <= BUCKETS_PER_LEVEL || level == MAX_NUMBER_OF_LEVELS);
+ }
+
+ @Override
+ RecordId getEntry(String key) {
+ checkNotNull(key);
+
+ if (size > 0) {
+ int hash = key.hashCode();
+ Segment segment = getSegment();
+
+ int index = 0;
+ while (index < size && getHash(segment, index) < hash) {
+ index++;
+ }
+ while (index < size && getHash(segment, index) == hash) {
+ if (key.equals(getKey(segment, index))) {
+ return getValue(segment, index);
+ }
+ index++;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ Iterable<String> getKeys() {
+ return new Iterable<String>() {
+ @Override
+ public Iterator<String> iterator() {
+ return getKeyIterator();
+ }
+
+ };
+ }
+
+ @Override
+ Iterable<Entry> getEntries() {
+ return new Iterable<Entry>() {
+ @Override
+ public Iterator<Entry> iterator() {
+ return getEntryIterator();
+ }
+ };
+ }
+
+ //-----------------------------------------------------------< private >--
+
+ private Iterator<String> getKeyIterator() {
+ return new Iterator<String>() {
+ private final Segment segment = getSegment();
+ private int index = 0;
+ @Override
+ public boolean hasNext() {
+ return index < size;
+ }
+ @Override
+ public String next() {
+ int i = index++;
+ if (i < size) {
+ return getKey(segment, i);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ private Iterator<Entry> getEntryIterator() {
+ return new Iterator<Entry>() {
+ private final Segment segment = getSegment();
+ private int index = 0;
+ @Override
+ public boolean hasNext() {
+ return index < size;
+ }
+ @Override
+ public Entry next() {
+ final int i = index++;
+ if (i < size) {
+ return new Entry() {
+ @Override
+ public String getKey() {
+ return MapLeaf.this.getKey(segment, i);
+ }
+ @Override
+ public RecordId getValue() {
+ return MapLeaf.this.getValue(segment, i);
+ }
+ @Override
+ public RecordId setValue(RecordId value) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ private int getHash(Segment segment, int index) {
+ return checkNotNull(segment).readInt(getOffset() + 4 + index * 4);
+ }
+
+ private String getKey(Segment segment, int index) {
+ int offset = getOffset() + 4 + size * 4 + index * RECORD_ID_BYTES;
+ RecordId id = checkNotNull(segment).readRecordId(offset);
+ if (!segment.getSegmentId().equals(id.getSegmentId())) {
+ // the string is stored in another segment
+ segment = store.readSegment(id.getSegmentId());
+ }
+ return segment.readString(id.getOffset());
+ }
+
+ private RecordId getValue(Segment segment, int index) {
+ int offset = getOffset()
+ + 4 + size * 4 + size * RECORD_ID_BYTES
+ + index * RECORD_ID_BYTES;
+ 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=1449014&r1=1449013&r2=1449014&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 Fri Feb 22 12:23:14 2013
@@ -16,145 +16,123 @@
*/
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 java.lang.Integer.highestOneBit;
+import static java.lang.Integer.numberOfTrailingZeros;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
import java.util.Map;
+import java.util.UUID;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
+abstract class MapRecord extends Record {
-class MapRecord extends Record {
+ /**
+ * Number of bits of the hash code to look at on each level of the trie.
+ */
+ protected static final int BITS_PER_LEVEL = 5;
+
+ /**
+ * Number of buckets at each level of the trie.
+ */
+ protected static final int BUCKETS_PER_LEVEL = 1 << BITS_PER_LEVEL; // 32
+
+ /**
+ * Maximum number of trie levels.
+ */
+ protected static final int MAX_NUMBER_OF_LEVELS =
+ (32 + BITS_PER_LEVEL - 1) / BITS_PER_LEVEL; // 7
+
+ /**
+ * Number of bits needed to indicate the current trie level.
+ */
+ protected static final int LEVEL_BITS = // 4, using nextPowerOfTwo():
+ numberOfTrailingZeros(highestOneBit(MAX_NUMBER_OF_LEVELS) << 1);
+
+ /**
+ * Number of bits used to indicate the size of a map.
+ */
+ protected static final int SIZE_BITS = 32 - LEVEL_BITS;
+
+ /**
+ * Maximum size of a map.
+ */
+ protected static final int MAX_SIZE = (1 << SIZE_BITS) - 1; // ~268e6
+
+ static MapRecord readMap(SegmentStore store, RecordId id) {
+ checkNotNull(store);
+ checkNotNull(id);
+
+ Segment segment = checkNotNull(store).readSegment(id.getSegmentId());
+ int head = segment.readInt(id.getOffset());
+ int level = head >>> SIZE_BITS;
+ int size = head & ((1 << SIZE_BITS) - 1);
+ System.out.println("R: " + size + " " + level);
+ if (size > BUCKETS_PER_LEVEL && level < MAX_NUMBER_OF_LEVELS) {
+ int bitmap = segment.readInt(id.getOffset() + 4);
+ return new MapBranch(store, id, size, level, bitmap);
+ } else {
+ return new MapLeaf(store, id, size, level);
+ }
+ }
public interface Entry extends Map.Entry<String, RecordId> {
}
- static final int LEVEL_BITS = 5;
+ protected final SegmentStore store;
- MapRecord(RecordId id) {
- super(id);
- }
+ protected final int size;
- public int size(SegmentReader reader) {
- return reader.readInt(getRecordId(), 0);
+ protected final int level;
+
+ protected MapRecord(SegmentStore store, RecordId id, int size, int level) {
+ super(checkNotNull(id));
+ this.store = checkNotNull(store);
+ this.size = checkElementIndex(size, MAX_SIZE);
+ this.level = checkElementIndex(level, MAX_NUMBER_OF_LEVELS);
}
- public RecordId getEntry(SegmentReader reader, String key) {
- checkNotNull(key);
- return getEntry(reader, key, 0);
+ protected Segment getSegment() {
+ return getSegment(getRecordId().getSegmentId());
}
- private int getHash(SegmentReader reader, int index) {
- return reader.readInt(getRecordId(), 4 + index * 4);
+ protected Segment getSegment(UUID uuid) {
+ return store.readSegment(uuid);
}
- private String getKey(SegmentReader reader, int size, int index) {
- int offset = 4 + size * 4 + index * Segment.RECORD_ID_BYTES;
- return reader.readString(reader.readRecordId(getRecordId(), offset));
+ protected int getOffset() {
+ return getRecordId().getOffset();
}
- private RecordId getValue(SegmentReader reader, int size, int index) {
- int offset = 4 + size * 4 + (size + index) * Segment.RECORD_ID_BYTES;
- return reader.readRecordId(getRecordId(), offset);
+ int size() {
+ return size;
}
- private RecordId getEntry(SegmentReader reader, String key, int level) {
- int size = 1 << LEVEL_BITS;
- int mask = size - 1;
- int shift = level * LEVEL_BITS;
+ abstract RecordId getEntry(String key);
- int code = key.hashCode();
- int bucketSize = reader.readInt(getRecordId(), 0);
- if (bucketSize == 0) {
- return null;
- } else if (bucketSize <= size || shift >= 32) {
- int index = 0;
- while (index < bucketSize && getHash(reader, index) < code) {
- index++;
- }
- while (index < bucketSize && getHash(reader, index) == code) {
- if (key.equals(getKey(reader, bucketSize, index))) {
- return getValue(reader, bucketSize, index);
- }
- index++;
- }
- return null;
- } else {
- int bucketMap = reader.readInt(getRecordId(), 4);
- int bucketIndex = (code >> shift) & mask;
- int bucketBit = 1 << bucketIndex;
- if ((bucketMap & bucketBit) != 0) {
- bucketIndex = Integer.bitCount(bucketMap & (bucketBit - 1));
- RecordId bucketId = reader.readRecordId(getRecordId(), 8 + bucketIndex * Segment.RECORD_ID_BYTES);
- return new MapRecord(bucketId).getEntry(reader, key, level + 1);
+ abstract Iterable<String> getKeys();
+
+ abstract Iterable<Entry> getEntries();
+
+ //------------------------------------------------------------< Object >--
+
+ @Override
+ public String toString() {
+ StringBuilder builder = null;
+ for (Entry entry : getEntries()) {
+ if (builder == null) {
+ builder = new StringBuilder("{ ");
} else {
- return null;
+ builder.append(", ");
}
+ builder.append(entry.getKey());
+ builder.append("=");
+ builder.append(entry.getValue());
}
- }
-
- public Iterable<Entry> getEntries(SegmentReader reader) {
- return getEntries(reader, 0);
- }
-
- private Iterable<Entry> getEntries(
- final SegmentReader reader, int level) {
- int size = 1 << LEVEL_BITS;
- int shift = level * LEVEL_BITS;
-
- final int bucketSize = reader.readInt(getRecordId(), 0);
- if (bucketSize == 0) {
- return Collections.emptyList();
- } else if (bucketSize <= size || shift >= 32) {
- return new Iterable<Entry>() {
- @Override
- public Iterator<Entry> iterator() {
- return new Iterator<Entry>() {
- private int index = 0;
- @Override
- public boolean hasNext() {
- return index < bucketSize;
- }
- @Override
- public Entry next() {
- final int i = index++;
- return new Entry() {
- @Override
- public String getKey() {
- return MapRecord.this.getKey(
- reader, bucketSize, i);
- }
- @Override
- public RecordId getValue() {
- return MapRecord.this.getValue(
- reader, bucketSize, i);
- }
- @Override
- public RecordId setValue(RecordId value) {
- throw new UnsupportedOperationException();
- }
- };
- }
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
+ if (builder == null) {
+ return "{}";
} else {
- int bucketMap = reader.readInt(getRecordId(), 4);
- int bucketCount = Integer.bitCount(bucketMap);
- List<Iterable<Entry>> iterables =
- Lists.newArrayListWithCapacity(bucketCount);
- for (int i = 0; i < bucketCount; i++) {
- RecordId bucketId = reader.readRecordId(
- getRecordId(), 8 + i * Segment.RECORD_ID_BYTES);
- iterables.add(new MapRecord(bucketId).getEntries(reader, level + 1));
- }
- return Iterables.concat(iterables);
+ builder.append(" }");
+ return builder.toString();
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MemoryStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MemoryStore.java?rev=1449014&r1=1449013&r2=1449014&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MemoryStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MemoryStore.java Fri Feb 22 12:23:14 2013
@@ -80,7 +80,7 @@ public class MemoryStore implements Segm
UUID segmentId, byte[] data, int offset, int length) {
byte[] segment = new byte[length];
System.arraycopy(data, offset, segment, 0, length);
- createSegment(new Segment(segmentId, segment, new UUID[0]));
+ createSegment(new Segment(this, segmentId, segment, new UUID[0]));
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MongoStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MongoStore.java?rev=1449014&r1=1449013&r2=1449014&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MongoStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MongoStore.java Fri Feb 22 12:23:14 2013
@@ -121,7 +121,7 @@ public class MongoStore implements Segme
for (int i = 0; i < uuids.length; i++) {
uuids[i] = UUID.fromString(list.get(i).toString());
}
- return new Segment(segmentId, data, uuids);
+ return new Segment(this, segmentId, data, uuids);
}
private void insertSegment(UUID segmentId, byte[] data, UUID[] uuids) {
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=1449014&r1=1449013&r2=1449014&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 Feb 22 12:23:14 2013
@@ -81,6 +81,8 @@ class Segment {
}
};
+ private final SegmentStore store;
+
private final UUID uuid;
private final byte[] data;
@@ -90,7 +92,8 @@ class Segment {
private final OffsetCache<String> strings = new OffsetCache<String>() {
@Override
protected String load(int offset) {
- return null;
+ return new SegmentReader(store).readString(
+ new RecordId(uuid, offset));
}
};
@@ -101,7 +104,8 @@ class Segment {
}
};
- Segment(UUID uuid, byte[] data, UUID[] uuids) {
+ Segment(SegmentStore store, UUID uuid, byte[] data, UUID[] uuids) {
+ this.store = store;
this.uuid = uuid;
this.data = data;
this.uuids = uuids;
@@ -168,4 +172,8 @@ class Segment {
return ByteBuffer.wrap(data).getLong(pos);
}
+ String readString(int offset) {
+ return strings.get(offset);
+ }
+
}
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=1449014&r1=1449013&r2=1449014&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 Fri Feb 22 12:23:14 2013
@@ -264,4 +264,8 @@ public class SegmentReader {
return new BlockRecord(recordId, size);
}
+ SegmentStore getStore() {
+ return store;
+ }
+
}
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=1449014&r1=1449013&r2=1449014&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 Fri Feb 22 12:23:14 2013
@@ -45,6 +45,7 @@ import org.apache.jackrabbit.oak.spi.sta
import org.apache.jackrabbit.oak.spi.state.NodeState;
import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;
@@ -102,7 +103,7 @@ public class SegmentWriter {
}
store.createSegment(new Segment(
- uuid, data, uuids.toArray(new UUID[uuids.size()])));
+ store, uuid, data, uuids.toArray(new UUID[uuids.size()])));
uuid = UUID.randomUUID();
length = 0;
@@ -230,29 +231,28 @@ public class SegmentWriter {
}
}
- private synchronized BucketInfo writeMapBucket(
+ private synchronized MapRecord writeMapBucket(
RecordId baseId, List<MapEntry> entries, int level) {
- int size = 1 << MapRecord.LEVEL_BITS;
- int mask = size - 1;
+ int mask = MapRecord.BUCKETS_PER_LEVEL - 1;
int shift = level * MapRecord.LEVEL_BITS;
if (entries.isEmpty()) {
if (baseId != null) {
- return new BucketInfo(baseId, new MapRecord(baseId).size(reader));
+ return MapRecord.readMap(store, baseId);
} else if (level == 0) {
RecordId id = prepare(4);
writeInt(0);
- return new BucketInfo(id, 0);
+ return new MapLeaf(store, id, 0, 0);
} else {
- return new BucketInfo(null, 0);
+ return null;
}
} else if (baseId != null) {
// FIXME: messy code with lots of duplication
- MapRecord base = new MapRecord(baseId);
- int baseSize = base.size(reader);
- if (baseSize <= size) {
+ MapRecord base = MapRecord.readMap(store, baseId);
+ int baseSize = base.size();
+ if (baseSize <= MapRecord.BUCKETS_PER_LEVEL) {
Map<String, RecordId> update = Maps.newHashMap();
- for (MapRecord.Entry entry : base.getEntries(reader)) {
+ for (MapRecord.Entry entry : base.getEntries()) {
update.put(entry.getKey(), entry.getValue());
}
for (MapEntry entry : entries) {
@@ -268,7 +268,7 @@ public class SegmentWriter {
}
return writeMapBucket(null, entries, level);
} else {
- List<MapEntry>[] buckets = new List[size];
+ List<MapEntry>[] buckets = new List[MapRecord.BUCKETS_PER_LEVEL];
for (MapEntry entry : entries) {
int bucketIndex = (entry.hashCode >> shift) & mask;
if (buckets[bucketIndex] == null) {
@@ -280,7 +280,7 @@ public class SegmentWriter {
int baseMap = reader.readInt(baseId, 4);
int newSize = 0;
- RecordId[] bucketIds = new RecordId[size];
+ RecordId[] bucketIds = new RecordId[MapRecord.BUCKETS_PER_LEVEL];
for (int i = 0; i < buckets.length; i++) {
int bucketBit = 1 << i;
RecordId baseBucketId = null;
@@ -290,14 +290,14 @@ public class SegmentWriter {
baseId, 8 + index * Segment.RECORD_ID_BYTES);
}
if (buckets[i] != null) {
- BucketInfo info = writeMapBucket(
+ MapRecord map = writeMapBucket(
baseBucketId, buckets[i], level + 1);
- bucketIds[i] = info.id;
- newSize += info.size;
+ bucketIds[i] = map.getRecordId();
+ newSize += map.size();
} else {
bucketIds[i] = baseBucketId;
if (baseBucketId != null) {
- newSize += new MapRecord(baseBucketId).size(reader);
+ newSize += MapRecord.readMap(store, baseBucketId).size();
}
}
}
@@ -312,14 +312,14 @@ public class SegmentWriter {
}
RecordId bucketId = prepare(12, ids);
- writeInt(newSize);
+ writeInt((level << MapRecord.SIZE_BITS) | newSize);
writeInt(bucketMap);
for (RecordId id : ids) {
writeRecordId(id);
}
- return new BucketInfo(bucketId, newSize);
+ return new MapBranch(store, bucketId, newSize, level, bucketMap);
}
- } else if (entries.size() <= size) {
+ } else if (entries.size() <= MapRecord.BUCKETS_PER_LEVEL) {
Collections.sort(entries);
List<RecordId> ids = Lists.newArrayList();
@@ -329,7 +329,9 @@ public class SegmentWriter {
}
RecordId bucketId = prepare(4 + entries.size() * 4, ids);
- writeInt(entries.size());
+ // System.out.println("W: " + entries.size() + " " + level);
+ Preconditions.checkState(entries.size() > 0 || level == 0);
+ writeInt((level << MapRecord.SIZE_BITS) | entries.size());
for (MapEntry entry : entries) {
writeInt(entry.hashCode);
}
@@ -339,9 +341,9 @@ public class SegmentWriter {
for (MapEntry entry : entries) {
writeRecordId(entry.value);
}
- return new BucketInfo(bucketId, entries.size());
+ return new MapLeaf(store, bucketId, entries.size(), level);
} else {
- List<MapEntry>[] buckets = new List[size];
+ List<MapEntry>[] buckets = new List[MapRecord.BUCKETS_PER_LEVEL];
for (MapEntry entry : entries) {
int bucketIndex = (entry.hashCode >> shift) & mask;
if (buckets[bucketIndex] == null) {
@@ -354,18 +356,18 @@ public class SegmentWriter {
int bucketMap = 0;
for (int i = 0; i < buckets.length; i++) {
if (buckets[i] != null) {
- bucketIds.add(writeMapBucket(null, buckets[i], level + 1).id);
+ bucketIds.add(writeMapBucket(null, buckets[i], level + 1).getRecordId());
bucketMap |= 1 << i;
}
}
RecordId bucketId = prepare(8, bucketIds);
- writeInt(entries.size());
+ writeInt((level << MapRecord.SIZE_BITS) | entries.size());
writeInt(bucketMap);
for (RecordId id : bucketIds) {
writeRecordId(id);
}
- return new BucketInfo(bucketId, entries.size());
+ return new MapBranch(store, bucketId, entries.size(), level, bucketMap);
}
}
@@ -427,7 +429,7 @@ public class SegmentWriter {
if (base != null) {
baseId = base.getRecordId();
}
- return new MapRecord(writeMapBucket(baseId, entries, 0).id);
+ return writeMapBucket(baseId, entries, 0);
}
/**
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=1449014&r1=1449013&r2=1449014&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 Fri Feb 22 12:23:14 2013
@@ -247,7 +247,7 @@ class Template {
} else if (hasManyChildNodes()) {
RecordId childNodesId =
reader.readRecordId(recordId, Segment.RECORD_ID_BYTES);
- return new MapRecord(childNodesId).size(reader);
+ return MapRecord.readMap(reader.getStore(), childNodesId).size();
} else {
return 1;
}
@@ -255,7 +255,8 @@ class Template {
MapRecord getChildNodeMap(SegmentReader reader, RecordId recordId) {
checkState(hasManyChildNodes());
- return new MapRecord(
+ return MapRecord.readMap(
+ reader.getStore(),
reader.readRecordId(recordId, Segment.RECORD_ID_BYTES));
}
@@ -265,7 +266,7 @@ class Template {
return false;
} else if (hasManyChildNodes()) {
MapRecord map = getChildNodeMap(reader, recordId);
- return map.getEntry(reader, name) != null;
+ return map.getEntry(name) != null;
} else {
return name.equals(childName);
}
@@ -277,7 +278,7 @@ class Template {
return null;
} else if (hasManyChildNodes()) {
RecordId childNodeId =
- getChildNodeMap(reader, recordId).getEntry(reader, name);
+ getChildNodeMap(reader, recordId).getEntry(name);
if (childNodeId != null) {
return new SegmentNodeState(reader, childNodeId);
} else {
@@ -297,14 +298,7 @@ class Template {
if (hasNoChildNodes()) {
return Collections.emptyList();
} else if (hasManyChildNodes()) {
- return Iterables.transform(
- getChildNodeMap(reader, recordId).getEntries(reader),
- new Function<MapRecord.Entry, String>() {
- @Override @Nullable
- public String apply(@Nullable Entry input) {
- return input.getKey();
- }
- });
+ return getChildNodeMap(reader, recordId).getKeys();
} else {
return Collections.singletonList(childName);
}
@@ -316,7 +310,7 @@ class Template {
return Collections.emptyList();
} else if (hasManyChildNodes()) {
return Iterables.transform(
- getChildNodeMap(reader, recordId).getEntries(reader),
+ getChildNodeMap(reader, recordId).getEntries(),
new Function<MapRecord.Entry, ChildNodeEntry>() {
@Override @Nullable
public ChildNodeEntry apply(@Nullable Entry input) {
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=1449014&r1=1449013&r2=1449014&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 Fri Feb 22 12:23:14 2013
@@ -187,54 +187,55 @@ public class RecordTest {
writer.flush();
Iterator<MapRecord.Entry> iterator;
- assertEquals(0, zero.size(reader));
- assertNull(zero.getEntry(reader, "one"));
- iterator = zero.getEntries(reader).iterator();
+ assertEquals(0, zero.size());
+ assertNull(zero.getEntry("one"));
+ iterator = zero.getEntries().iterator();
assertFalse(iterator.hasNext());
- assertEquals(1, one.size(reader));
- assertEquals(blockId, one.getEntry(reader, "one"));
- assertNull(one.getEntry(reader, "two"));
- iterator = one.getEntries(reader).iterator();
+ assertEquals(1, one.size());
+ assertEquals(blockId, one.getEntry("one"));
+ assertNull(one.getEntry("two"));
+ iterator = one.getEntries().iterator();
assertTrue(iterator.hasNext());
assertEquals("one", iterator.next().getKey());
assertFalse(iterator.hasNext());
- assertEquals(2, two.size(reader));
- assertEquals(blockId, two.getEntry(reader, "one"));
- assertEquals(blockId, two.getEntry(reader, "two"));
- assertNull(two.getEntry(reader, "three"));
- iterator = two.getEntries(reader).iterator();
+ assertEquals(2, two.size());
+ assertEquals(blockId, two.getEntry("one"));
+ assertEquals(blockId, two.getEntry("two"));
+ assertNull(two.getEntry("three"));
+ iterator = two.getEntries().iterator();
assertTrue(iterator.hasNext());
iterator.next();
assertTrue(iterator.hasNext());
iterator.next();
assertFalse(iterator.hasNext());
- assertEquals(1000, many.size(reader));
- iterator = many.getEntries(reader).iterator();
+ assertEquals(1000, many.size());
+ iterator = many.getEntries().iterator();
+ System.out.println(MapRecord.readMap(store, many.getRecordId()));
for (int i = 0; i < 1000; i++) {
assertTrue(iterator.hasNext());
assertEquals(blockId, iterator.next().getValue());
- assertEquals(blockId, many.getEntry(reader, "key" + i));
+ assertEquals(blockId, many.getEntry("key" + i));
}
assertFalse(iterator.hasNext());
- assertNull(many.getEntry(reader, "foo"));
+ assertNull(many.getEntry("foo"));
Map<String, RecordId> changes = Maps.newHashMap();
changes.put("key0", null);
changes.put("key1000", blockId);
MapRecord modified = writer.writeMap(many, changes);
writer.flush();
- assertEquals(1000, modified.size(reader));
- iterator = modified.getEntries(reader).iterator();
+ assertEquals(1000, modified.size());
+ iterator = modified.getEntries().iterator();
for (int i = 1; i <= 1000; i++) {
assertTrue(iterator.hasNext());
assertEquals(blockId, iterator.next().getValue());
- assertEquals(blockId, modified.getEntry(reader, "key" + i));
+ assertEquals(blockId, modified.getEntry("key" + i));
}
assertFalse(iterator.hasNext());
- assertNull(many.getEntry(reader, "foo"));
+ assertNull(many.getEntry("foo"));
}
@Test
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=1449014&r1=1449013&r2=1449014&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 Feb 22 12:23:14 2013
@@ -156,7 +156,7 @@ public class SegmentSizeTest {
SegmentNodeState state = writer.writeNode(builder.getNodeState());
writer.flush();
Segment segment = store.readSegment(state.getRecordId().getSegmentId());
- assertEquals(28588, segment.getData().length);
+ assertEquals(26788, segment.getData().length);
builder = state.builder();
builder.child("child1000");