Author: alexparvulescu Date: Tue Nov 19 10:41:23 2013 New Revision: 1543371
URL: http://svn.apache.org/r1543371 Log: OAK-1137 Node.getReferences() is slow due to missing property index Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java (with props) jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java (with props) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/AbstractTree.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/IdentifierManager.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceEditor.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java jackrabbit/oak/trunk/oak-jcr/pom.xml jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/AbstractTree.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/AbstractTree.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/AbstractTree.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/AbstractTree.java Tue Nov 19 10:41:23 2013 @@ -28,6 +28,7 @@ import org.apache.jackrabbit.mk.api.Micr import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.plugins.index.IndexConstants; +import org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants; import org.apache.jackrabbit.oak.spi.state.NodeBuilder; import org.apache.jackrabbit.oak.spi.state.NodeState; @@ -57,6 +58,8 @@ public abstract class AbstractTree imple // TODO: make this configurable private static final String[] INTERNAL_NODE_NAMES = { IndexConstants.INDEX_CONTENT_NODE_NAME, + NodeReferenceConstants.REF_NAME, + NodeReferenceConstants.WEAK_REF_NAME, MicroKernel.CONFLICT_NAME}; /** Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/IdentifierManager.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/IdentifierManager.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/IdentifierManager.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/IdentifierManager.java Tue Nov 19 10:41:23 2013 @@ -27,7 +27,6 @@ import java.text.ParseException; import java.util.Collections; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.UUID; import javax.annotation.CheckForNull; @@ -38,7 +37,6 @@ import javax.jcr.query.Query; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.collect.Iterators; -import com.google.common.collect.Sets; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.PropertyValue; @@ -51,6 +49,7 @@ import org.apache.jackrabbit.oak.commons import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.plugins.memory.StringPropertyState; import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager; +import org.apache.jackrabbit.oak.plugins.version.VersionConstants; import org.apache.jackrabbit.oak.spi.query.PropertyValues; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -188,23 +187,21 @@ public class IdentifierManager { * specified {@code tree} and matching the constraints. */ @Nonnull - public Set<String> getReferences(boolean weak, Tree tree, final String propertyName, final String... nodeTypeNames) { + public Iterable<String> getReferences(boolean weak, Tree tree, final String propertyName, final String... nodeTypeNames) { if (!nodeTypeManager.isNodeType(tree, JcrConstants.MIX_REFERENCEABLE)) { return Collections.emptySet(); // shortcut } - try { - final String uuid = getIdentifier(tree); - String reference = weak ? PropertyType.TYPENAME_WEAKREFERENCE : PropertyType.TYPENAME_REFERENCE; - String pName = propertyName == null ? "*" : propertyName; // TODO: sanitize against injection attacks!? - Map<String, ? extends PropertyValue> bindings = Collections.singletonMap("uuid", PropertyValues.newString(uuid)); + final String uuid = getIdentifier(tree); + String reference = weak ? PropertyType.TYPENAME_WEAKREFERENCE : PropertyType.TYPENAME_REFERENCE; + String pName = propertyName == null ? "*" : propertyName; // TODO: sanitize against injection attacks!? + Map<String, ? extends PropertyValue> bindings = Collections.singletonMap("uuid", PropertyValues.newString(uuid)); + try { Result result = root.getQueryEngine().executeQuery( "SELECT * FROM [nt:base] WHERE PROPERTY([" + pName + "], '" + reference + "') = $uuid", Query.JCR_SQL2, Long.MAX_VALUE, 0, bindings, new NamePathMapper.Default()); - - Iterable<String> paths = findPaths(result, uuid, propertyName, nodeTypeNames); - return Sets.newHashSet(paths); + return findPaths(result, uuid, propertyName, nodeTypeNames); } catch (ParseException e) { log.error("query failed", e); return Collections.emptySet(); @@ -242,7 +239,7 @@ public class IdentifierManager { } // skip references from the version storage (OAK-1196) - if (!rowPath.startsWith("/jcr:system/jcr:versionStorage/")) { + if (!rowPath.startsWith(VersionConstants.VERSION_STORE_PATH)) { Tree tree = root.getTree(rowPath); if (nodeTypeNames.length == 0 || containsNodeType(tree, nodeTypeNames)) { if (propertyName == null) { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java Tue Nov 19 10:41:23 2013 @@ -115,10 +115,10 @@ public class ContentMirrorStoreStrategy builder.setProperty("match", true); } - @Override - public Iterable<String> query(final Filter filter, final String indexName, - final NodeState indexMeta, final Iterable<String> values) { - final NodeState index = indexMeta.getChildNode(INDEX_CONTENT_NODE_NAME); + public Iterable<String> query(final Filter filter, final String indexName, + final NodeState indexMeta, final String indexStorageNodeName, + final Iterable<String> values) { + final NodeState index = indexMeta.getChildNode(indexStorageNodeName); return new Iterable<String>() { @Override public Iterator<String> iterator() { @@ -142,8 +142,19 @@ public class ContentMirrorStoreStrategy } @Override + public Iterable<String> query(final Filter filter, final String indexName, + final NodeState indexMeta, final Iterable<String> values) { + return query(filter, indexName, indexMeta, INDEX_CONTENT_NODE_NAME, values); + } + + @Override public long count(NodeState indexMeta, Set<String> values, int max) { - NodeState index = indexMeta.getChildNode(INDEX_CONTENT_NODE_NAME); + return count(indexMeta, INDEX_CONTENT_NODE_NAME, values, max); + } + + public long count(NodeState indexMeta, final String indexStorageNodeName, + Set<String> values, int max) { + NodeState index = indexMeta.getChildNode(indexStorageNodeName); int count = 0; if (values == null) { PropertyState ec = indexMeta.getProperty(ENTRY_COUNT_PROPERTY_NAME); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceEditor.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceEditor.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceEditor.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceEditor.java Tue Nov 19 10:41:23 2013 @@ -16,8 +16,10 @@ */ package org.apache.jackrabbit.oak.plugins.index.reference; +import static com.google.common.collect.ImmutableSet.of; import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Sets.newHashSet; +import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM; import static org.apache.jackrabbit.JcrConstants.JCR_UUID; import static org.apache.jackrabbit.oak.api.CommitFailedException.INTEGRITY; import static org.apache.jackrabbit.oak.api.Type.REFERENCE; @@ -28,8 +30,10 @@ import static org.apache.jackrabbit.oak. import static org.apache.jackrabbit.oak.api.Type.WEAKREFERENCES; import static org.apache.jackrabbit.oak.commons.PathUtils.concat; import static org.apache.jackrabbit.oak.commons.PathUtils.elements; +import static org.apache.jackrabbit.oak.commons.PathUtils.isAbsolute; import static org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants.REF_NAME; import static org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants.WEAK_REF_NAME; +import static org.apache.jackrabbit.oak.plugins.version.VersionConstants.SYSTEM_PATHS; import java.util.Map; import java.util.Map.Entry; @@ -37,12 +41,11 @@ import java.util.Set; import javax.annotation.Nonnull; -import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.core.ImmutableRoot; import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager; -import org.apache.jackrabbit.oak.plugins.version.VersionConstants; +import org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy; import org.apache.jackrabbit.oak.spi.commit.DefaultEditor; import org.apache.jackrabbit.oak.spi.commit.Editor; import org.apache.jackrabbit.oak.spi.state.NodeBuilder; @@ -54,9 +57,7 @@ import org.apache.jackrabbit.oak.spi.sta */ class ReferenceEditor extends DefaultEditor { - // TODO - // - look into using a storage strategy (trees) - // - what happens when you move a node? who updates the backlinks? + private static ContentMirrorStoreStrategy STORE = new ContentMirrorStoreStrategy(); /** Parent editor, or {@code null} if this is the root editor. */ private final ReferenceEditor parent; @@ -111,6 +112,13 @@ class ReferenceEditor extends DefaultEdi */ private final Set<String> discardedIds; + /** + * set of ids that were added during this commit. we need it to reconcile + * moves + * + */ + private final Set<String> newIds; + public ReferenceEditor(NodeBuilder builder) { this.parent = null; this.name = null; @@ -123,6 +131,7 @@ class ReferenceEditor extends DefaultEdi this.rmWeakRefs = newHashMap(); this.rmIds = newHashSet(); this.discardedIds = newHashSet(); + this.newIds = newHashSet(); } private ReferenceEditor(ReferenceEditor parent, String name, String uuid) { @@ -137,6 +146,7 @@ class ReferenceEditor extends DefaultEdi this.rmWeakRefs = parent.rmWeakRefs; this.rmIds = parent.rmIds; this.discardedIds = parent.discardedIds; + this.newIds = parent.newIds; } /** @@ -174,6 +184,7 @@ class ReferenceEditor extends DefaultEdi if (parent == null) { Set<String> offending = newHashSet(rmIds); offending.removeAll(rmRefs.keySet()); + offending.removeAll(newIds); if (!offending.isEmpty()) { throw new CommitFailedException(INTEGRITY, 1, "Unable to delete referenced node"); @@ -198,7 +209,7 @@ class ReferenceEditor extends DefaultEdi if (newRefs.containsKey(uuid)) { add = newRefs.remove(uuid); } - set(child, REF_NAME, add, rm); + update(child, REF_NAME, uuid, add, rm); } for (Entry<String, Set<String>> ref : newRefs.entrySet()) { String uuid = ref.getKey(); @@ -213,7 +224,7 @@ class ReferenceEditor extends DefaultEdi } Set<String> add = ref.getValue(); Set<String> rm = newHashSet(); - set(child, REF_NAME, add, rm); + update(child, REF_NAME, uuid, add, rm); } for (Entry<String, Set<String>> ref : rmWeakRefs.entrySet()) { String uuid = ref.getKey(); @@ -231,7 +242,7 @@ class ReferenceEditor extends DefaultEdi if (newWeakRefs.containsKey(uuid)) { add = newWeakRefs.remove(uuid); } - set(child, WEAK_REF_NAME, add, rm); + update(child, WEAK_REF_NAME, uuid, add, rm); } for (Entry<String, Set<String>> ref : newWeakRefs.entrySet()) { String uuid = ref.getKey(); @@ -246,7 +257,7 @@ class ReferenceEditor extends DefaultEdi } Set<String> add = ref.getValue(); Set<String> rm = newHashSet(); - set(child, WEAK_REF_NAME, add, rm); + update(child, WEAK_REF_NAME, uuid, add, rm); } } } @@ -260,11 +271,13 @@ class ReferenceEditor extends DefaultEdi public void propertyChanged(PropertyState before, PropertyState after) { if (before != null) { if (before.getType() == REFERENCE || before.getType() == REFERENCES) { - put(rmRefs, before.getValue(STRINGS), concat(getPath(), before.getName())); + put(rmRefs, before.getValue(STRINGS), + concat(getPath(), before.getName())); } if (before.getType() == WEAKREFERENCE || before.getType() == WEAKREFERENCES) { - put(rmWeakRefs, before.getValue(STRINGS), concat(getPath(), before.getName())); + put(rmWeakRefs, before.getValue(STRINGS), + concat(getPath(), before.getName())); } if (JCR_UUID.equals(before.getName())) { // node remove + add -> changed uuid @@ -276,11 +289,13 @@ class ReferenceEditor extends DefaultEdi } if (after != null) { if (after.getType() == REFERENCE || after.getType() == REFERENCES) { - put(newRefs, after.getValue(STRINGS), concat(getPath(), after.getName())); + put(newRefs, after.getValue(STRINGS), + concat(getPath(), after.getName())); } if (after.getType() == WEAKREFERENCE || after.getType() == WEAKREFERENCES) { - put(newWeakRefs, after.getValue(STRINGS), concat(getPath(), after.getName())); + put(newWeakRefs, after.getValue(STRINGS), + concat(getPath(), after.getName())); } } } @@ -296,7 +311,11 @@ class ReferenceEditor extends DefaultEdi if (isVersionStorePath(path)) { return null; } - return new ReferenceEditor(this, name, after.getString(JCR_UUID)); + String uuid = after.getString(JCR_UUID); + if (uuid != null) { + newIds.add(uuid); + } + return new ReferenceEditor(this, name, uuid); } @Override @@ -317,10 +336,8 @@ class ReferenceEditor extends DefaultEdi return null; } String uuid = before.getString(JCR_UUID); - if (before.hasProperty(REF_NAME)) { - if (uuid != null) { - rmIds.add(uuid); - } + if (uuid != null && check(before, REF_NAME, uuid)) { + rmIds.add(uuid); } return new ReferenceEditor(this, name, uuid); } @@ -354,8 +371,8 @@ class ReferenceEditor extends DefaultEdi } private static boolean isVersionStorePath(@Nonnull String oakPath) { - if (oakPath.indexOf(JcrConstants.JCR_SYSTEM) == 1) { - for (String p : VersionConstants.SYSTEM_PATHS) { + if (oakPath.indexOf(JCR_SYSTEM) == 1) { + for (String p : SYSTEM_PATHS) { if (oakPath.startsWith(p)) { return true; } @@ -366,35 +383,32 @@ class ReferenceEditor extends DefaultEdi private static void put(Map<String, Set<String>> map, Iterable<String> keys, String value) { + String asRelative = isAbsolute(value) ? value.substring(1) : value; for (String key : keys) { Set<String> values = map.get(key); if (values == null) { values = newHashSet(); } - values.add(value); + values.add(asRelative); map.put(key, values); } } - private static void set(NodeBuilder child, String name, Set<String> add, - Set<String> rm) { - // TODO should we optimize for the remove/add case? intersect the - // sets, work on the diffs? - - Set<String> vals; - PropertyState ref = child.getProperty(name); - if (ref != null) { - vals = newHashSet(ref.getValue(STRINGS)); - } else { - vals = newHashSet(); - } - vals.addAll(add); - vals.removeAll(rm); - if (!vals.isEmpty()) { - child.setProperty(name, vals, STRINGS); - } else { - child.removeProperty(name); + private static void update(NodeBuilder child, String name, String key, + Set<String> add, Set<String> rm) { + NodeBuilder index = child.child(name); + Set<String> empty = of(); + for (String p : add) { + // TODO do we still need to encode the values? + STORE.update(index, p, empty, of(key)); + } + for (String p : rm) { + STORE.update(index, p, of(key), empty); } } + private static boolean check(NodeState ns, String name, String key) { + return ns.hasChildNode(name) && STORE.count(ns, name, of(key), 1) > 0; + } + } Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java?rev=1543371&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java (added) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java Tue Nov 19 10:41:23 2013 @@ -0,0 +1,151 @@ +/* + * 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.index.reference; + +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static java.lang.Double.POSITIVE_INFINITY; +import static javax.jcr.PropertyType.REFERENCE; +import static javax.jcr.PropertyType.WEAKREFERENCE; +import static org.apache.jackrabbit.oak.api.Type.STRING; +import static org.apache.jackrabbit.oak.commons.PathUtils.elements; +import static org.apache.jackrabbit.oak.commons.PathUtils.getName; +import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; +import static org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants.REF_NAME; +import static org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants.WEAK_REF_NAME; +import static org.apache.jackrabbit.oak.spi.query.Cursors.newPathCursor; + +import java.util.ArrayList; + +import org.apache.jackrabbit.oak.core.ImmutableRoot; +import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager; +import org.apache.jackrabbit.oak.plugins.index.property.strategy.ContentMirrorStoreStrategy; +import org.apache.jackrabbit.oak.query.index.FilterImpl; +import org.apache.jackrabbit.oak.spi.query.Cursor; +import org.apache.jackrabbit.oak.spi.query.Filter; +import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction; +import org.apache.jackrabbit.oak.spi.query.QueryIndex; +import org.apache.jackrabbit.oak.spi.state.NodeState; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; + +/** + * Provides a QueryIndex that does lookups for node references based on a custom + * index saved on hidden property names + * + */ +class ReferenceIndex implements QueryIndex { + + private static ContentMirrorStoreStrategy STORE = new ContentMirrorStoreStrategy(); + + @Override + public String getIndexName() { + return "reference"; + } + + @Override + public double getCost(Filter filter, NodeState root) { + // TODO don't call getCost for such queries + if (filter.getFullTextConstraint() != null) { + // not an appropriate index for full-text search + return POSITIVE_INFINITY; + } + for (PropertyRestriction pr : filter.getPropertyRestrictions()) { + if (pr.propertyType == REFERENCE + || pr.propertyType == WEAKREFERENCE) { + return 1; + } + } + // not an appropriate index + return POSITIVE_INFINITY; + } + + @Override + public Cursor query(Filter filter, NodeState root) { + for (PropertyRestriction pr : filter.getPropertyRestrictions()) { + if (pr.propertyType == REFERENCE) { + String uuid = pr.first.getValue(STRING); + String name = pr.propertyName; + return lookup(root, uuid, name, REF_NAME); + } + if (pr.propertyType == WEAKREFERENCE) { + String uuid = pr.first.getValue(STRING); + String name = pr.propertyName; + return lookup(root, uuid, name, WEAK_REF_NAME); + } + } + return newPathCursor(new ArrayList<String>()); + } + + private static Cursor lookup(NodeState state, String uuid, + final String name, String index) { + String path = getIdManager(state).resolveUUID(uuid); + NodeState child = state; + for (String p : elements(path)) { + child = child.getChildNode(p); + } + if (!child.exists()) { + return newPathCursor(new ArrayList<String>()); + } + Iterable<String> paths = STORE.query(new FilterImpl(), index + "(" + + uuid + ")", child, index, null); + + if (!"*".equals(name)) { + paths = filter(paths, new Predicate<String>() { + @Override + public boolean apply(String path) { + return name.equals(getName(path)); + } + }); + } + paths = transform(paths, new Function<String, String>() { + @Override + public String apply(String path) { + return getParentPath(path); + } + }); + return newPathCursor(paths); + } + + private static IdentifierManager getIdManager(NodeState state) { + return new IdentifierManager(new ImmutableRoot(state)); + } + + @Override + public String getPlan(Filter filter, NodeState root) { + StringBuilder buff = new StringBuilder("reference"); + for (PropertyRestriction pr : filter.getPropertyRestrictions()) { + if (pr.propertyType == REFERENCE) { + buff.append(" PROPERTY(["); + buff.append(pr.propertyName); + buff.append("], 'Reference') = "); + buff.append(pr.first.getValue(STRING)); + return buff.toString(); + } + if (pr.propertyType == WEAKREFERENCE) { + buff.append(" PROPERTY(["); + buff.append(pr.propertyName); + buff.append("], 'WeakReference') = "); + buff.append(pr.first.getValue(STRING)); + return buff.toString(); + } + } + return buff.toString(); + } + +} \ No newline at end of file Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndex.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java?rev=1543371&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java (added) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java Tue Nov 19 10:41:23 2013 @@ -0,0 +1,43 @@ +/* + * 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.index.reference; + +import java.util.List; + +import javax.annotation.Nonnull; + +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.apache.jackrabbit.oak.spi.query.QueryIndex; +import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider; +import org.apache.jackrabbit.oak.spi.state.NodeState; + +import com.google.common.collect.ImmutableList; + +/** + * A provider for node references indices. + */ +@Component +@Service(QueryIndexProvider.class) +public class ReferenceIndexProvider implements QueryIndexProvider { + + @Override + @Nonnull + public List<QueryIndex> getQueryIndexes(NodeState state) { + return ImmutableList.<QueryIndex> of(new ReferenceIndex()); + } +} Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/reference/ReferenceIndexProvider.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipProvider.java Tue Nov 19 10:41:23 2013 @@ -101,7 +101,7 @@ class MembershipProvider extends Authori @Nonnull Iterator<String> getMembership(Tree authorizableTree, boolean includeInherited) { Set<String> groupPaths = new HashSet<String>(); - Set<String> refPaths = identifierManager.getReferences(true, authorizableTree, REP_MEMBERS, NT_REP_GROUP, NT_REP_MEMBERS); + Iterable<String> refPaths = identifierManager.getReferences(true, authorizableTree, REP_MEMBERS, NT_REP_GROUP, NT_REP_MEMBERS); for (String propPath : refPaths) { int index = propPath.indexOf('/' + REP_MEMBERS); if (index > 0) { Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java Tue Nov 19 10:41:23 2013 @@ -44,6 +44,8 @@ import org.apache.jackrabbit.oak.api.Roo import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider; import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider; +import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider; +import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceIndexProvider; import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider; import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent; import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl; @@ -78,6 +80,8 @@ public abstract class AbstractSecurityTe public void before() throws Exception { Oak oak = new Oak() .with(new InitialContent()) + .with(new ReferenceEditorProvider()) + .with(new ReferenceIndexProvider()) .with(new PropertyIndexEditorProvider()) .with(new PropertyIndexProvider()) .with(new RegistrationEditorProvider()) Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/pom.xml (original) +++ jackrabbit/oak/trunk/oak-jcr/pom.xml Tue Nov 19 10:41:23 2013 @@ -50,9 +50,6 @@ org.apache.jackrabbit.test.api.WorkspaceMoveSameNameSibsTest#testMoveNodesOrderingSupportedByParent <!-- OAK-118 --> org.apache.jackrabbit.test.api.WorkspaceMoveTest#testMoveNodesLocked <!-- OAK-118 --> - org.apache.jackrabbit.oak.jcr.ReferencesTest#testMovedReferences <!-- OAK-1195 --> - org.apache.jackrabbit.oak.jcr.ReferencesTest#testMovedVersionedReferences <!-- OAK-1195 --> - <!-- Locking : not fully implemented --> org.apache.jackrabbit.test.api.lock.LockTest#testNodeLocked org.apache.jackrabbit.test.api.lock.LockTest#testParentChildDeepLock @@ -96,7 +93,6 @@ org.apache.jackrabbit.test.api.version.RestoreTest#testRestoreLabel org.apache.jackrabbit.test.api.version.RestoreTest#testRestoreLabelJcr2 org.apache.jackrabbit.test.api.version.WorkspaceRestoreTest - org.apache.jackrabbit.test.api.version.GetReferencesNodeTest#testGetReferencesNeverFromVersions <!-- Node.getReferences must not return references from version storage --> org.apache.jackrabbit.test.api.version.MergeCancelMergeTest org.apache.jackrabbit.test.api.version.MergeCheckedoutSubNodeTest org.apache.jackrabbit.test.api.version.MergeDoneMergeTest @@ -176,9 +172,6 @@ <!-- Node Types --> org.apache.jackrabbit.oak.jcr.nodetype.MixinTest#testRemoveAddMixVersionable1 <!-- OAK-1118 --> - - org.apache.jackrabbit.test.api.SessionUUIDTest#testSaveReferentialIntegrityException <!-- OAK-685 --> - org.apache.jackrabbit.test.api.NodeUUIDTest#testSaveReferentialIntegrityException <!-- OAK-685 --> </known.issues> </properties> Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java Tue Nov 19 10:41:23 2013 @@ -32,6 +32,8 @@ import org.apache.jackrabbit.oak.plugins import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider; import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider; import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider; +import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider; +import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceIndexProvider; import org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider; import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider; import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider; @@ -70,6 +72,8 @@ public class Jcr { with(new TypeEditorProvider()); with(new RegistrationEditorProvider()); with(new ConflictValidatorProvider()); + with(new ReferenceEditorProvider()); + with(new ReferenceIndexProvider()); with(new PropertyIndexEditorProvider()); Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java?rev=1543371&r1=1543370&r2=1543371&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java Tue Nov 19 10:41:23 2013 @@ -748,7 +748,7 @@ public class NodeImpl<T extends NodeDele public PropertyIterator perform() throws InvalidItemStateException { IdentifierManager idManager = sessionDelegate.getIdManager(); - Set<String> propertyOakPaths = idManager.getReferences(weak, node.getTree(), name); // TODO: oak name? + Iterable<String> propertyOakPaths = idManager.getReferences(weak, node.getTree(), name); // TODO: oak name? Iterable<Property> properties = Iterables.transform( propertyOakPaths, new Function<String, Property>() { @@ -760,7 +760,7 @@ public class NodeImpl<T extends NodeDele } ); - return new PropertyIteratorAdapter(properties.iterator(), propertyOakPaths.size()); + return new PropertyIteratorAdapter(properties.iterator()); } }); }
