commit c9db4190d25f038fda16649f78e54f45780d2ac9 Author: Florent Guillaume Date: Thu Nov 30 19:44:58 2017 +0100 NXP-23788: optimize Read ACL update on big volume diff --git a/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicQuerySimpleBuilder.java b/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicQuerySimpleBuilder.java index 569e836..3563dc4 100644 --- a/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicQuerySimpleBuilder.java +++ b/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicQuerySimpleBuilder.java @@ -42,6 +42,10 @@ class MarkLogicQuerySimpleBuilder { private final List rangeElementIndexes; + protected int limit; + + protected int offset; + public MarkLogicQuerySimpleBuilder(List rangeElementIndexes) { this.queries = new ArrayList<>(); this.rangeElementIndexes = rangeElementIndexes; @@ -104,8 +108,22 @@ class MarkLogicQuerySimpleBuilder { return Arrays.stream(values).map(serializer).collect(Collectors.joining(",", "(", ")")); } + public MarkLogicQuerySimpleBuilder limit(int limit) { + this.limit = limit; + return this; + } + + public MarkLogicQuerySimpleBuilder offset(int offset) { + this.offset = offset; + return this; + } + public String build() { - return String.format("cts:search(fn:doc(),cts:and-query((%s)))", String.join(",", queries)); + String searchQuery = String.format("cts:search(fn:doc(),cts:and-query((%s)))", String.join(",", queries)); + if (limit != 0) { + searchQuery = String.format("%s[%s to %s]", searchQuery, offset + 1, offset + limit); + } + return searchQuery; } } diff --git a/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicRepository.java b/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicRepository.java index 08037d7..35ec950 100644 --- a/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicRepository.java +++ b/src/main/java/org/nuxeo/ecm/core/storage/marklogic/MarkLogicRepository.java @@ -34,6 +34,7 @@ import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -43,6 +44,7 @@ import java.util.Spliterator; import java.util.UUID; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -177,11 +179,19 @@ public class MarkLogicRepository extends DBSRepositoryBase { @Override public State readState(String id) { + return readPartialState(id, null); + } + + @Override + public State readPartialState(String id, Collection keys) { if (log.isTraceEnabled()) { log.trace("MarkLogic: READ " + id); } try (Session session = xccContentSource.newSession()) { String query = "fn:doc('" + ID_FORMATTER.apply(id) + "')"; + if (keys != null && !keys.isEmpty()) { + query = getProjectedQuery(query, keys); + } AdhocQuery request = session.newAdhocQuery(query); // ResultSequence will be closed by Session close ResultSequence rs = session.submitRequest(request); @@ -322,8 +332,14 @@ public class MarkLogicRepository extends DBSRepositoryBase { @Override public void queryKeyValueArray(String key, Object value, Set ids, Map proxyTargets, Map targetProxies) { + queryKeyValueArray(key, value, ids, proxyTargets, targetProxies, 0); + } + + @Override + public void queryKeyValueArray(String key, Object value, Set ids, Map proxyTargets, + Map targetProxies, int limit) { MarkLogicQuerySimpleBuilder builder = new MarkLogicQuerySimpleBuilder(rangeElementIndexes); - builder.eq(key, value); + builder.eq(key, value).limit(limit); try (Stream states = findAll(builder.build(), KEY_ID, KEY_IS_PROXY, KEY_PROXY_TARGET_ID, KEY_PROXY_IDS)) { states.forEach(state -> { @@ -669,14 +685,7 @@ public class MarkLogicRepository extends DBSRepositoryBase { protected Stream findAll(String ctsQuery, String... selects) { String query = ctsQuery; if (selects.length > 0) { - query = "import module namespace extract = 'http://nuxeo.com/extract' at '/ext/nuxeo/extract.xqy';\n" - + "let $paths := (" + Arrays.stream(selects) - .map(MarkLogicHelper::serializeKey) - .map(select -> "\"" + MarkLogicHelper.DOCUMENT_ROOT_PATH + "/" + select - + "\"") - .collect(Collectors.joining(",\n")) - + ")let $namespaces := ()\n" + "for $i in " + query - + " return extract:extract-nodes($i, $paths, $namespaces)"; + query = getProjectedQuery(query, Arrays.asList(selects)); } if (log.isTraceEnabled()) { logQuery(query); @@ -718,4 +727,21 @@ public class MarkLogicRepository extends DBSRepositoryBase { } } + protected static final String PATH_COLLECTOR_BEGIN = "\"" + MarkLogicHelper.DOCUMENT_ROOT_PATH + "/"; + + protected static final String PATH_COLLECTOR_END = "\""; + + protected static final String PATH_COLLECTOR_SEP = ",\n"; + + protected static final Collector PATH_COLLECTOR = Collectors.joining( + PATH_COLLECTOR_END + PATH_COLLECTOR_SEP + PATH_COLLECTOR_BEGIN, PATH_COLLECTOR_BEGIN, PATH_COLLECTOR_END); + + protected String getProjectedQuery(String query, Collection keys) { + String paths = keys.stream().map(MarkLogicHelper::serializeKey).collect(PATH_COLLECTOR); + return "import module namespace extract = 'http://nuxeo.com/extract' at '/ext/nuxeo/extract.xqy';\n" + + "let $paths := (" + paths + ")\n" // + + "let $namespaces := ()\n" // + + "for $i in " + query + " return extract:extract-nodes($i, $paths, $namespaces)"; + } + }