Author: jukka
Date: Fri Jul 19 10:45:02 2013
New Revision: 1504822
URL: http://svn.apache.org/r1504822
Log:
OAK-922: Optimize UpdateManyChildNodesTest
Avoid copying already existing value records when updating just some entries in
a multi-valued property in SegmentMK
Modified:
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/SegmentWriter.java
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=1504822&r1=1504821&r2=1504822&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
Fri Jul 19 10:45:02 2013
@@ -19,11 +19,15 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Collections.emptyMap;
import java.util.Iterator;
+import java.util.Map;
import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
+import javax.jcr.PropertyType;
import org.apache.jackrabbit.oak.api.AbstractPropertyState;
import org.apache.jackrabbit.oak.api.Type;
@@ -49,6 +53,37 @@ class SegmentPropertyState extends Abstr
return recordId;
}
+ private ListRecord getValueList() {
+ RecordId listId = recordId;
+ int size = 1;
+ 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);
+ }
+
+ Map<String, RecordId> getValueRecords() {
+ if (getType().tag() == PropertyType.BINARY) {
+ return emptyMap();
+ }
+
+ Map<String, RecordId> map = newHashMap();
+
+ ListRecord values = getValueList();
+ Segment segment = store.readSegment(recordId.getSegmentId());
+ SegmentReader reader = new SegmentReader(store);
+ for (int i = 0; i < values.size(); i++) {
+ RecordId valueId = values.getEntry(reader, i);
+ String value = segment.readString(valueId);
+ map.put(value, valueId);
+ }
+
+ return map;
+ }
@Override @Nonnull
public String getName() {
@@ -119,25 +154,20 @@ class SegmentPropertyState extends Abstr
checkNotNull(type);
checkArgument(!type.isArray(), "Type must not be an array type");
- Segment segment = store.readSegment(recordId.getSegmentId());
+ ListRecord values = getValueList();
+ checkElementIndex(index, values.size());
Type<?> base = getType();
- ListRecord values;
if (base.isArray()) {
base = base.getBaseType();
- int size = segment.readInt(recordId.getOffset());
- RecordId listId = segment.readRecordId(recordId.getOffset() + 4);
- values = new ListRecord(listId, size);
- } else {
- values = new ListRecord(recordId, 1);
}
- checkElementIndex(index, values.size());
SegmentReader reader = new SegmentReader(store);
RecordId valueId = values.getEntry(reader, index);
if (type == Type.BINARY) {
return (T) new SegmentBlob(reader, valueId);
} else {
+ Segment segment = store.readSegment(recordId.getSegmentId());
String value = segment.readString(valueId);
if (type == Type.STRING || type == Type.URI
|| type == Type.NAME || type == Type.PATH
@@ -174,15 +204,7 @@ class SegmentPropertyState extends Abstr
@Override
public long size(int index) {
- ListRecord values;
- if (isArray()) {
- Segment segment = store.readSegment(recordId.getSegmentId());
- int size = segment.readInt(recordId.getOffset());
- RecordId listId = segment.readRecordId(recordId.getOffset() + 4);
- values = new ListRecord(listId, size);
- } else {
- values = new ListRecord(recordId, 1);
- }
+ ListRecord values = getValueList();
checkElementIndex(index, values.size());
SegmentReader reader = new SegmentReader(store);
return reader.readLength(values.getEntry(reader, 0));
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=1504822&r1=1504821&r2=1504822&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 Jul 19 10:45:02 2013
@@ -22,6 +22,8 @@ import static com.google.common.base.Pre
import static com.google.common.base.Preconditions.checkPositionIndex;
import static com.google.common.base.Preconditions.checkPositionIndexes;
import static com.google.common.base.Preconditions.checkState;
+import static java.util.Collections.emptyMap;
+import static javax.jcr.PropertyType.BINARY;
import static
org.apache.jackrabbit.oak.plugins.segment.MapRecord.BUCKETS_PER_LEVEL;
import static
org.apache.jackrabbit.oak.plugins.segment.Segment.MAX_SEGMENT_SIZE;
@@ -515,7 +517,8 @@ public class SegmentWriter {
}
}
- private synchronized RecordId writeProperty(PropertyState state) {
+ private synchronized RecordId writeProperty(
+ PropertyState state, Map<String, RecordId> previousValues) {
Type<?> type = state.getType();
int count = state.count();
@@ -529,7 +532,12 @@ public class SegmentWriter {
throw new IllegalStateException("Unexpected IOException",
e);
}
} else {
- valueIds.add(writeString(state.getValue(Type.STRING, i)));
+ String value = state.getValue(Type.STRING, i);
+ RecordId valueId = previousValues.get(value);
+ if (valueId == null) {
+ valueId = writeString(value);
+ }
+ valueIds.add(valueId);
}
}
@@ -688,22 +696,26 @@ public class SegmentWriter {
}
for (PropertyTemplate pt : template.getPropertyTemplates()) {
- RecordId propertyId = null;
String name = pt.getName();
PropertyState property = state.getProperty(name);
- if (before != null) {
- // reuse previously stored property record, if possible
- PropertyState beforeProperty = before.getProperty(name);
- if (beforeProperty instanceof SegmentPropertyState
- && property.equals(beforeProperty)) {
- propertyId = ((SegmentPropertyState) beforeProperty)
- .getRecordId();
+
+ if (property instanceof SegmentPropertyState) {
+ ids.add(((SegmentPropertyState) property).getRecordId());
+ } else {
+ Map<String, RecordId> previousValues = emptyMap();
+ if (before != null) {
+ // reuse previously stored property values, if possible
+ PropertyState beforeProperty = before.getProperty(name);
+ if (beforeProperty instanceof SegmentPropertyState
+ && beforeProperty.isArray()
+ && beforeProperty.getType() != Type.BINARIES) {
+ SegmentPropertyState segmentProperty =
+ (SegmentPropertyState) beforeProperty;
+ previousValues = segmentProperty.getValueRecords();
+ }
}
+ ids.add(writeProperty(property, previousValues));
}
- if (propertyId == null) {
- propertyId = writeProperty(property);
- }
- ids.add(propertyId);
}
RecordId recordId = prepare(0, ids);