Author: jukka
Date: Tue Dec 10 19:56:29 2013
New Revision: 1549950
URL: http://svn.apache.org/r1549950
Log:
OAK-593: Segment-based MK
Optimized code for accessing property values
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentPropertyState.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1549950&r1=1549949&r2=1549950&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
Tue Dec 10 19:56:29 2013
@@ -417,40 +417,22 @@ public class MemoryNodeBuilder implement
@Override
public boolean getBoolean(String name) {
- PropertyState property = getProperty(name);
- return property != null
- && property.getType() == BOOLEAN
- && property.getValue(BOOLEAN);
+ return head().getCurrentNodeState().getBoolean(checkNotNull(name));
}
@Override @CheckForNull
public String getString(@Nonnull String name) {
- PropertyState property = getProperty(name);
- if (property != null && property.getType() == STRING) {
- return property.getValue(STRING);
- } else {
- return null;
- }
+ return head().getCurrentNodeState().getString(checkNotNull(name));
}
@Override @CheckForNull
public String getName(@Nonnull String name) {
- PropertyState property = getProperty(name);
- if (property != null && property.getType() == NAME) {
- return property.getValue(NAME);
- } else {
- return null;
- }
+ return head().getCurrentNodeState().getName(checkNotNull(name));
}
- @Override
+ @Override @Nonnull
public Iterable<String> getNames(@Nonnull String name) {
- PropertyState property = getProperty(name);
- if (property != null && property.getType() == NAMES) {
- return property.getValue(NAMES);
- } else {
- return emptyList();
- }
+ return head().getCurrentNodeState().getNames(checkNotNull(name));
}
@Override
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java?rev=1549950&r1=1549949&r2=1549950&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/ListRecord.java
Tue Dec 10 19:56:29 2013
@@ -18,6 +18,11 @@ 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.collect.Lists.newArrayListWithCapacity;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
+import java.util.List;
class ListRecord extends Record {
@@ -58,4 +63,28 @@ class ListRecord extends Record {
}
}
+ public List<RecordId> getEntries() {
+ if (size == 0) {
+ return emptyList();
+ } else if (size == 1) {
+ return singletonList(getRecordId());
+ } else {
+ List<RecordId> list = newArrayListWithCapacity(size);
+ Segment segment = getSegment();
+ int offset = getOffset();
+ for (int i = 0; i < size; i += bucketSize) {
+ RecordId id = segment.readRecordId(offset);
+ if (bucketSize == 1) {
+ list.add(id);
+ } else {
+ ListRecord bucket = new ListRecord(
+ segment, id, Math.min(bucketSize, size - offset));
+ list.addAll(bucket.getEntries());
+ }
+ offset += Segment.RECORD_ID_BYTES;
+ }
+ return list;
+ }
+ }
+
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java?rev=1549950&r1=1549949&r2=1549950&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeState.java
Tue Dec 10 19:56:29 2013
@@ -18,10 +18,12 @@ package org.apache.jackrabbit.oak.plugin
import java.util.Collections;
import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -31,8 +33,16 @@ import org.apache.jackrabbit.oak.spi.sta
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Lists.newArrayListWithCapacity;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
+import static org.apache.jackrabbit.oak.api.Type.LONG;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
import static
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
@@ -108,21 +118,21 @@ public class SegmentNodeState extends Re
return template.getPrimaryType();
} else if (JCR_MIXINTYPES.equals(name)) {
return template.getMixinTypes();
- } else {
- PropertyTemplate propertyTemplate =
- template.getPropertyTemplate(name);
- if (propertyTemplate != null) {
- Segment segment = getSegment();
- int ids = 1 + propertyTemplate.getIndex();
- if (template.getChildName() != Template.ZERO_CHILD_NODES) {
- ids++;
- }
- return new SegmentPropertyState(
- segment, segment.readRecordId(getOffset(0, ids)),
- propertyTemplate);
- } else {
- return null;
+ }
+
+ PropertyTemplate propertyTemplate =
+ template.getPropertyTemplate(name);
+ if (propertyTemplate != null) {
+ Segment segment = getSegment();
+ int ids = 1 + propertyTemplate.getIndex();
+ if (template.getChildName() != Template.ZERO_CHILD_NODES) {
+ ids++;
}
+ return new SegmentPropertyState(
+ segment, segment.readRecordId(getOffset(0, ids)),
+ propertyTemplate);
+ } else {
+ return null;
}
}
@@ -159,32 +169,137 @@ public class SegmentNodeState extends Re
@Override
public boolean getBoolean(String name) {
- return AbstractNodeState.getBoolean(this, name);
+ return Boolean.TRUE.toString().equals(getValueAsString(name, BOOLEAN));
}
@Override
public long getLong(String name) {
- return AbstractNodeState.getLong(this, name);
+ String value = getValueAsString(name, LONG);
+ if (value != null) {
+ return Long.parseLong(value);
+ } else {
+ return 0;
+ }
}
- @Override
+ @Override @CheckForNull
public String getString(String name) {
- return AbstractNodeState.getString(this, name);
+ return getValueAsString(name, STRING);
}
- @Override
+ @Override @Nonnull
public Iterable<String> getStrings(String name) {
- return AbstractNodeState.getStrings(this, name);
+ return getValuesAsStrings(name, STRINGS);
}
- @Override
+ @Override @CheckForNull
public String getName(String name) {
- return AbstractNodeState.getName(this, name);
+ return getValueAsString(name, NAME);
}
- @Override
+ @Override @Nonnull
public Iterable<String> getNames(String name) {
- return AbstractNodeState.getNames(this, name);
+ return getValuesAsStrings(name, NAMES);
+ }
+
+ /**
+ * Optimized value access method. Returns the string value of a property
+ * of a given non-array type. Returns {@code null} if the named property
+ * does not exist, or is of a different type than given.
+ *
+ * @param name property name
+ * @param type property type
+ * @return string value of the property, or {@code null}
+ */
+ @CheckForNull
+ private String getValueAsString(String name, Type<?> type) {
+ checkArgument(!type.isArray());
+
+ Template template = getTemplate();
+ if (JCR_PRIMARYTYPE.equals(name)) {
+ PropertyState primary = template.getPrimaryType();
+ if (type == NAME) {
+ return primary.getValue(NAME);
+ } else if (primary != null) {
+ return null;
+ }
+ } else if (JCR_MIXINTYPES.equals(name)
+ && template.getMixinTypes() != null) {
+ return null;
+ }
+
+ PropertyTemplate propertyTemplate =
+ template.getPropertyTemplate(name);
+ if (propertyTemplate == null
+ || propertyTemplate.getType() != type) {
+ return null;
+ }
+
+ Segment segment = getSegment();
+ int ids = 1 + propertyTemplate.getIndex();
+ if (template.getChildName() != Template.ZERO_CHILD_NODES) {
+ ids++;
+ }
+ return segment.readString(segment.readRecordId(getOffset(0, ids)));
+ }
+
+ /**
+ * Optimized value access method. Returns the string values of a property
+ * of a given array type. Returns an empty iterable if the named property
+ * does not exist, or is of a different type than given.
+ *
+ * @param name property name
+ * @param type property type
+ * @return string values of the property, or an empty iterable
+ */
+ @Nonnull
+ private Iterable<String> getValuesAsStrings(String name, Type<?> type) {
+ checkArgument(type.isArray());
+
+ Template template = getTemplate();
+ if (JCR_MIXINTYPES.equals(name)) {
+ PropertyState mixin = template.getMixinTypes();
+ if (type == NAMES && mixin != null) {
+ return mixin.getValue(NAMES);
+ } else if (type == NAMES || mixin != null) {
+ return emptyList();
+ }
+ } else if (JCR_PRIMARYTYPE.equals(name)
+ && template.getPrimaryType() != null) {
+ return emptyList();
+ }
+
+ PropertyTemplate propertyTemplate =
+ template.getPropertyTemplate(name);
+ if (propertyTemplate == null
+ || propertyTemplate.getType() != type) {
+ return emptyList();
+ }
+
+ Segment segment = getSegment();
+ int ids = 1 + propertyTemplate.getIndex();
+ if (template.getChildName() != Template.ZERO_CHILD_NODES) {
+ ids++;
+ }
+
+ RecordId id = segment.readRecordId(getOffset(0, ids));
+ segment = segment.getSegment(id);
+ int size = segment.readInt(id.getOffset());
+ if (size == 0) {
+ return emptyList();
+ }
+
+ id = segment.readRecordId(id.getOffset() + 4);
+ if (size == 1) {
+ return singletonList(segment.readString(id));
+ }
+
+ List<String> values = newArrayListWithCapacity(size);
+ ListRecord list = new ListRecord(segment, id, size);
+ for (RecordId value : list.getEntries()) {
+ values.add(segment.readString(value));
+ }
+ return values;
}
@Override
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=1549950&r1=1549949&r2=1549950&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
Tue Dec 10 19:56:29 2013
@@ -19,12 +19,27 @@ 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.base.Preconditions.checkState;
+import static com.google.common.collect.Lists.newArrayListWithCapacity;
import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonList;
+import static org.apache.jackrabbit.oak.api.Type.BINARY;
+import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
+import static org.apache.jackrabbit.oak.api.Type.DATE;
+import static org.apache.jackrabbit.oak.api.Type.DECIMAL;
+import static org.apache.jackrabbit.oak.api.Type.DOUBLE;
+import static org.apache.jackrabbit.oak.api.Type.LONG;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.PATH;
+import static org.apache.jackrabbit.oak.api.Type.REFERENCE;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.URI;
+import static org.apache.jackrabbit.oak.api.Type.WEAKREFERENCE;
-import java.util.Iterator;
+import java.util.List;
import java.util.Map;
-import java.util.NoSuchElementException;
import javax.annotation.Nonnull;
import javax.jcr.PropertyType;
@@ -101,35 +116,31 @@ class SegmentPropertyState extends Recor
@Override @Nonnull @SuppressWarnings("unchecked")
public <T> T getValue(Type<T> type) {
- if (type.isArray()) {
- final int count = count();
- final Type<?> base = type.getBaseType();
- return (T) new Iterable<Object>() {
- @Override
- public Iterator<Object> iterator() {
- return new Iterator<Object>() {
- private int index = 0;
- @Override
- public boolean hasNext() {
- return index < count;
- }
- @Override
- public Object next() {
- if (hasNext()) {
- return getValue(base, index++);
- } else {
- throw new NoSuchElementException();
- }
- }
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
+ Segment segment = getSegment();
+ if (isArray()) {
+ checkState(type.isArray());
+ ListRecord values = getValueList(segment);
+ if (values.size() == 0) {
+ return (T) emptyList();
+ } else if (values.size() == 1) {
+ return (T) singletonList(getValue(
+ segment, values.getEntry(0), type.getBaseType()));
+ } else {
+ Type<?> base = type.getBaseType();
+ List<Object> list = newArrayListWithCapacity(values.size());
+ for (RecordId id : values.getEntries()) {
+ list.add(getValue(segment, id, base));
}
- };
+ return (T) list;
+ }
} else {
- return getValue(type, 0);
+ RecordId id = getRecordId();
+ if (type.isArray()) {
+ return (T) singletonList(
+ getValue(segment, id, type.getBaseType()));
+ } else {
+ return getValue(segment, id, type);
+ }
}
}
@@ -138,7 +149,7 @@ class SegmentPropertyState extends Recor
return size(0);
}
- @Override @Nonnull @SuppressWarnings("unchecked")
+ @Override @Nonnull
public <T> T getValue(Type<T> type, int index) {
checkNotNull(type);
checkArgument(!type.isArray(), "Type must not be an array type");
@@ -146,36 +157,38 @@ class SegmentPropertyState extends Recor
Segment segment = getSegment();
ListRecord values = getValueList(segment);
checkElementIndex(index, values.size());
+ return getValue(segment, values.getEntry(index), type);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T getValue(Segment segment, RecordId id, Type<T> type) {
+ if (type == BINARY) {
+ return (T) new SegmentBlob(segment, id); // load binaries lazily
+ }
+
+ String value = segment.readString(id);
+ if (type == STRING || type == URI || type == DATE
+ || type == NAME || type == PATH
+ || type == REFERENCE || type == WEAKREFERENCE) {
+ return (T) value; // no conversion needed for string types
+ }
Type<?> base = getType();
if (base.isArray()) {
base = base.getBaseType();
}
-
- RecordId valueId = values.getEntry(index);
- if (type == Type.BINARY) {
- return (T) new SegmentBlob(segment, valueId);
+ Converter converter = Conversions.convert(value, base);
+ if (type == BOOLEAN) {
+ return (T) Boolean.valueOf(converter.toBoolean());
+ } else if (type == DECIMAL) {
+ return (T) converter.toDecimal();
+ } else if (type == DOUBLE) {
+ return (T) Double.valueOf(converter.toDouble());
+ } else if (type == LONG) {
+ return (T) Long.valueOf(converter.toLong());
} else {
- String value = segment.readString(valueId);
- if (type == Type.STRING || type == Type.URI || type == Type.DATE
- || type == Type.NAME || type == Type.PATH
- || type == Type.REFERENCE || type == Type.WEAKREFERENCE) {
- return (T) value;
- } else {
- Converter converter = Conversions.convert(value, base);
- if (type == Type.BOOLEAN) {
- return (T) Boolean.valueOf(converter.toBoolean());
- } else if (type == Type.DECIMAL) {
- return (T) converter.toDecimal();
- } else if (type == Type.DOUBLE) {
- return (T) Double.valueOf(converter.toDouble());
- } else if (type == Type.LONG) {
- return (T) Long.valueOf(converter.toLong());
- } else {
- throw new UnsupportedOperationException(
- "Unknown type: " + type);
- }
- }
+ throw new UnsupportedOperationException(
+ "Unknown type: " + type);
}
}