Author: mreutegg
Date: Thu Jan 11 13:32:01 2018
New Revision: 1820877

URL: http://svn.apache.org/viewvc?rev=1820877&view=rev
Log:
OAK-7140: Retry query on MongoException

Modified:
    
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/RetryReadIT.java

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1820877&r1=1820876&r2=1820877&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 Thu Jan 11 13:32:01 2018
@@ -220,6 +220,13 @@ public class MongoDocumentStore implemen
     private int bulkRetries =
             Integer.getInteger("oak.mongo.bulkRetries", 0);
 
+    /**
+     * How many times a query to MongoDB should be retried when it fails with a
+     * MongoException.
+     */
+    private final int queryRetries =
+            Integer.getInteger("oak.mongo.queryRetries", 2);
+
     private String lastReadWriteMode;
 
     private final Map<String, String> metadata;
@@ -429,7 +436,7 @@ public class MongoDocumentStore implemen
                                        final int maxCacheAge) {
         if (collection != Collection.NODES) {
             return findUncachedWithRetry(collection, key,
-                    DocumentReadPreference.PRIMARY, 2);
+                    DocumentReadPreference.PRIMARY);
         }
         NodeDocument doc;
         if (maxCacheAge > 0 || preferCached) {
@@ -467,7 +474,7 @@ public class MongoDocumentStore implemen
                 }
                 final NodeDocument d = (NodeDocument) findUncachedWithRetry(
                         collection, key,
-                        getReadPreference(maxCacheAge), 2);
+                        getReadPreference(maxCacheAge));
                 invalidateCache(collection, key);
                 doc = nodesCache.get(key, new Callable<NodeDocument>() {
                     @Override
@@ -500,20 +507,17 @@ public class MongoDocumentStore implemen
      * @param collection the collection to read from.
      * @param key the key of the document to find.
      * @param docReadPref the read preference.
-     * @param retries the number of retries. Must not be negative.
      * @param <T> the document type of the given collection.
      * @return the document or {@code null} if the document doesn't exist.
      */
     @CheckForNull
     private <T extends Document> T findUncachedWithRetry(
             Collection<T> collection, String key,
-            DocumentReadPreference docReadPref,
-            int retries) {
-        checkArgument(retries >= 0, "retries must not be negative");
+            DocumentReadPreference docReadPref) {
         if (key.equals("0:/")) {
             LOG.trace("root node");
         }
-        int numAttempts = retries + 1;
+        int numAttempts = queryRetries + 1;
         MongoException ex = null;
         for (int i = 0; i < numAttempts; i++) {
             if (i > 0) {
@@ -581,11 +585,40 @@ public class MongoDocumentStore implemen
                                               String indexedProperty,
                                               long startValue,
                                               int limit) {
-        try {
-            return queryInternal(collection, fromKey, toKey, indexedProperty,
-                    startValue, limit, maxQueryTimeMS);
-        } catch (MongoException e) {
-            throw handleException(e, collection, Lists.newArrayList(fromKey, 
toKey));
+        return queryWithRetry(collection, fromKey, toKey, indexedProperty,
+                startValue, limit, maxQueryTimeMS);
+    }
+
+    /**
+     * Queries for documents and performs a number of retries if the read fails
+     * with an exception.
+     */
+    @Nonnull
+    private <T extends Document> List<T> queryWithRetry(Collection<T> 
collection,
+                                                        String fromKey,
+                                                        String toKey,
+                                                        String indexedProperty,
+                                                        long startValue,
+                                                        int limit,
+                                                        long maxQueryTime) {
+        int numAttempts = queryRetries + 1;
+        MongoException ex = null;
+        for (int i = 0; i < numAttempts; i++) {
+            if (i > 0) {
+                LOG.warn("Retrying query, fromKey={}, toKey={}", fromKey, 
toKey);
+            }
+            try {
+                return queryInternal(collection, fromKey, toKey,
+                        indexedProperty, startValue, limit, maxQueryTime);
+            } catch (MongoException e) {
+                ex = e;
+            }
+        }
+        if (ex != null) {
+            throw handleException(ex, collection, Lists.newArrayList(fromKey, 
toKey));
+        } else {
+            // impossible to get here
+            throw new IllegalStateException();
         }
     }
 

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/RetryReadIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/RetryReadIT.java?rev=1820877&r1=1820876&r2=1820877&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/RetryReadIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/RetryReadIT.java
 Thu Jan 11 13:32:01 2018
@@ -16,6 +16,10 @@
  */
 package org.apache.jackrabbit.oak.plugins.document.mongo;
 
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest;
 import org.apache.jackrabbit.oak.plugins.document.Collection;
 import org.apache.jackrabbit.oak.plugins.document.Document;
@@ -30,7 +34,10 @@ import com.mongodb.DB;
 import com.mongodb.MongoException;
 
 import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static org.hamcrest.collection.IsEmptyCollection.empty;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
@@ -69,6 +76,29 @@ public class RetryReadIT extends Abstrac
         }
     }
 
+    @Test
+    public void retryQuery() {
+        String fromKey = Utils.getKeyLowerLimit("/foo");
+        String toKey = Utils.getKeyUpperLimit("/foo");
+        // must survive two consecutive failures. -> 2 retries
+        store.failRead = 2;
+        List<NodeDocument> docs = store.query(NODES, fromKey, toKey, 100);
+        assertThat(docs, is(empty()));
+
+        fromKey = Utils.getKeyLowerLimit("/bar");
+        toKey = Utils.getKeyUpperLimit("/bar");
+        // must fail with three consecutive failures
+        store.failRead = 3;
+        try {
+            store.query(NODES, fromKey, toKey, 100);
+            fail("must fail with DocumentStoreException");
+        } catch (DocumentStoreException e) {
+            // expected
+        } finally {
+            store.failRead = 0;
+        }
+    }
+
     private static class TestStore extends MongoDocumentStore {
 
         private int failRead = 0;
@@ -81,12 +111,29 @@ public class RetryReadIT extends Abstrac
         protected <T extends Document> T findUncached(Collection<T> collection,
                                                       String key,
                                                       DocumentReadPreference 
docReadPref) {
+            maybeFail();
+            return super.findUncached(collection, key, docReadPref);
+        }
+
+        @Nonnull
+        @Override
+        protected <T extends Document> List<T> queryInternal(Collection<T> 
collection,
+                                                             String fromKey,
+                                                             String toKey,
+                                                             String 
indexedProperty,
+                                                             long startValue,
+                                                             int limit,
+                                                             long 
maxQueryTime) {
+            maybeFail();
+            return super.queryInternal(collection, fromKey, toKey,
+                    indexedProperty, startValue, limit, maxQueryTime);
+        }
+
+        private void maybeFail() {
             if (failRead > 0) {
                 failRead--;
                 throw new MongoException("read failed");
             }
-            return super.findUncached(collection, key, docReadPref);
         }
     }
-
 }


Reply via email to