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);
         }
     }
 


Reply via email to