You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2015/06/30 17:01:39 UTC

svn commit: r1688469 - in /jackrabbit/oak/branches/1.2: ./ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreTest.java

Author: mreutegg
Date: Tue Jun 30 15:01:39 2015
New Revision: 1688469

URL: http://svn.apache.org/r1688469
Log:
OAK-3023: Long running MongoDB query may block other threads

Merged revision 1688453 from trunk

Added:
    jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreTest.java
      - copied unchanged from r1688453, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreTest.java
Modified:
    jackrabbit/oak/branches/1.2/   (props changed)
    jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java

Propchange: jackrabbit/oak/branches/1.2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jun 30 15:01:39 2015
@@ -1,3 +1,3 @@
 /jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414-1673415,1673436,1673644,1673662-1673664,1673669,1673695,1673738,1673787,1673791,1674046,1674065,1674075,1674107,1674228,1674780,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677804,1677806,1677939,1677991,1678173,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679232,1679235,1679958,1679961,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680805-1680806,1680903,1681282,1681767,1681918,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683059,1683089,1683213,1683249,1683259,1683278,1683323,1683687,1683700,1684174-1684175,1684186,1684376,1684442,1684561,1684570,1684601,1684618,1684868,1685023,1685370,1685552,1685589,1685840,1685999,1686097,1686162,1686229,1686234,1686253,1686414,1686780
 ,1686854,1686857,1686971,1687053-1687055,1687198,1687220,1687239-1687240,1687301,1687441,1687553,1688089-1688090,1688349,1688421,1688436
+/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414-1673415,1673436,1673644,1673662-1673664,1673669,1673695,1673738,1673787,1673791,1674046,1674065,1674075,1674107,1674228,1674780,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677804,1677806,1677939,1677991,1678173,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679232,1679235,1679958,1679961,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680805-1680806,1680903,1681282,1681767,1681918,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683059,1683089,1683213,1683249,1683259,1683278,1683323,1683687,1683700,1684174-1684175,1684186,1684376,1684442,1684561,1684570,1684601,1684618,1684868,1685023,1685370,1685552,1685589,1685840,1685999,1686097,1686162,1686229,1686234,1686253,1686414,1686780
 ,1686854,1686857,1686971,1687053-1687055,1687198,1687220,1687239-1687240,1687301,1687441,1687553,1688089-1688090,1688349,1688421,1688436,1688453
 /jackrabbit/trunk:1345480

Modified: jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1688469&r1=1688468&r2=1688469&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java Tue Jun 30 15:01:39 2015
@@ -43,6 +43,7 @@ import com.google.common.collect.Immutab
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.UncheckedExecutionException;
 import com.mongodb.MongoClientURI;
+import com.mongodb.MongoExecutionTimeoutException;
 import com.mongodb.QueryOperators;
 import com.mongodb.ReadPreference;
 
@@ -173,6 +174,17 @@ public class MongoDocumentStore implemen
     private final long maxQueryTimeMS =
             Long.getLong("oak.mongo.maxQueryTimeMS", TimeUnit.MINUTES.toMillis(1));
 
+    /**
+     * Duration in milliseconds after a mongo query with an additional
+     * constraint (e.g. _modified) on the NODES collection times out and is
+     * executed again without holding a {@link TreeLock} and without updating
+     * the cache with data retrieved from MongoDB.
+     * <p>
+     * Default is 3000 (three seconds).
+     */
+    private long maxLockedQueryTimeMS =
+            Long.getLong("oak.mongo.maxLockedQueryTimeMS", TimeUnit.SECONDS.toMillis(3));
+
     private String lastReadWriteMode;
 
     private final Map<String, String> metadata;
@@ -489,6 +501,36 @@ public class MongoDocumentStore implemen
                                               String indexedProperty,
                                               long startValue,
                                               int limit) {
+        boolean withLock = true;
+        if (collection == Collection.NODES && indexedProperty != null) {
+            long maxQueryTime;
+            if (maxQueryTimeMS > 0) {
+                maxQueryTime = Math.min(maxQueryTimeMS, maxLockedQueryTimeMS);
+            } else {
+                maxQueryTime = maxLockedQueryTimeMS;
+            }
+            try {
+                return queryInternal(collection, fromKey, toKey, indexedProperty,
+                        startValue, limit, maxQueryTime, true);
+            } catch (MongoExecutionTimeoutException e) {
+                LOG.info("query timed out after {} milliseconds and will be retried without lock {}",
+                        maxQueryTime, Lists.newArrayList(fromKey, toKey, indexedProperty, startValue, limit));
+                withLock = false;
+            }
+        }
+        return queryInternal(collection, fromKey, toKey, indexedProperty,
+                startValue, limit, maxQueryTimeMS, withLock);
+    }
+
+    @Nonnull
+    <T extends Document> List<T> queryInternal(Collection<T> collection,
+                                                       String fromKey,
+                                                       String toKey,
+                                                       String indexedProperty,
+                                                       long startValue,
+                                                       int limit,
+                                                       long maxQueryTime,
+                                                       boolean withLock) {
         log("query", fromKey, toKey, indexedProperty, startValue, limit);
         DBCollection dbCollection = getDBCollection(collection);
         QueryBuilder queryBuilder = QueryBuilder.start(Document.ID);
@@ -518,16 +560,16 @@ public class MongoDocumentStore implemen
         }
         DBObject query = queryBuilder.get();
         String parentId = Utils.getParentIdFromLowerLimit(fromKey);
-        TreeLock lock = acquireExclusive(parentId != null ? parentId : "");
         final long start = PERFLOG.start();
+        TreeLock lock = withLock ? acquireExclusive(parentId != null ? parentId : "") : null;
         try {
             DBCursor cursor = dbCollection.find(query).sort(BY_ID_ASC);
             if (!disableIndexHint) {
                 cursor.hint(hint);
             }
-            if (maxQueryTimeMS > 0) {
+            if (maxQueryTime > 0) {
                 // OAK-2614: set maxTime if maxQueryTimeMS > 0
-                cursor.maxTime(maxQueryTimeMS, TimeUnit.MILLISECONDS);
+                cursor.maxTime(maxQueryTime, TimeUnit.MILLISECONDS);
             }
             ReadPreference readPreference =
                     getMongoReadPreference(collection, parentId, getDefaultReadPreference(collection));
@@ -544,7 +586,9 @@ public class MongoDocumentStore implemen
                 for (int i = 0; i < limit && cursor.hasNext(); i++) {
                     DBObject o = cursor.next();
                     T doc = convertFromDBObject(collection, o);
-                    if (collection == Collection.NODES && doc != null) {
+                    if (collection == Collection.NODES
+                            && doc != null
+                            && lock != null) {
                         doc.seal();
                         String id = doc.getId();
                         CacheValue cacheKey = new StringValue(id);
@@ -573,7 +617,9 @@ public class MongoDocumentStore implemen
             }
             return list;
         } finally {
-            lock.unlock();
+            if (lock != null) {
+                lock.unlock();
+            }
             PERFLOG.end(start, 1, "query for children from [{}] to [{}]", fromKey, toKey);
         }
     }
@@ -1303,6 +1349,10 @@ public class MongoDocumentStore implemen
         this.clock = clock;
     }
 
+    void setMaxLockedQueryTimeMS(long maxLockedQueryTimeMS) {
+        this.maxLockedQueryTimeMS = maxLockedQueryTimeMS;
+    }
+
     private final static class TreeLock {
 
         private final Lock parentLock;