Author: mreutegg Date: Wed Mar 7 08:37:19 2018 New Revision: 1826086 URL: http://svn.apache.org/viewvc?rev=1826086&view=rev Log: OAK-7308: Retry commit on transient DocumentStoreException
Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java?rev=1826086&r1=1826085&r2=1826086&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java Wed Mar 7 08:37:19 2018 @@ -347,7 +347,15 @@ class DocumentNodeStoreBranch implements if (msg == null) { msg = "Failed to merge changes to the underlying store"; } - return new CommitFailedException(OAK, 1, msg, t); + String type = OAK; + if (t instanceof DocumentStoreException) { + DocumentStoreException dse = (DocumentStoreException) t; + if (dse.getType() == DocumentStoreException.Type.TRANSIENT) { + // set type to MERGE, which indicates a retry may work + type = MERGE; + } + } + return new CommitFailedException(type, 1, msg, t); } /** Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1826086&r1=1826085&r2=1826086&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java Wed Mar 7 08:37:19 2018 @@ -24,6 +24,7 @@ import static org.apache.jackrabbit.oak. import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS; +import static org.apache.jackrabbit.oak.plugins.document.DocumentStoreException.Type.TRANSIENT; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS_RESOLUTION; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.NUM_REVS_THRESHOLD; @@ -3604,6 +3605,38 @@ public class DocumentNodeStoreTest { ); } + @Test + public void retryOnTransientDocumentStoreException() { + FailingDocumentStore store = new FailingDocumentStore(new MemoryDocumentStore()); + DocumentNodeStore ns = builderProvider.newBuilder() + .setAsyncDelay(0).setDocumentStore(store).getNodeStore(); + NodeBuilder builder = ns.getRoot().builder(); + builder.child("foo"); + + store.fail().after(0).once(); + try { + merge(ns, builder); + fail("CommitFailedException expected"); + } catch (CommitFailedException e) { + // expected + } finally { + store.fail().never(); + } + + builder = ns.getRoot().builder(); + builder.child("bar"); + + store.fail().after(0).withType(TRANSIENT).once(); + try { + merge(ns, builder); + } catch (CommitFailedException e) { + fail(e.toString()); + } finally { + store.fail().never(); + } + assertTrue(ns.getRoot().hasChildNode("bar")); + } + private void getChildNodeCountTest(int numChildren, Iterable<Long> maxValues, Iterable<Long> expectedValues) Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java?rev=1826086&r1=1826085&r2=1826086&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java Wed Mar 7 08:37:19 2018 @@ -23,6 +23,8 @@ import java.util.concurrent.atomic.Atomi import com.google.common.collect.Lists; +import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException.Type; + import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; @@ -39,6 +41,8 @@ class FailingDocumentStore extends Docum private AtomicLong numFailures = new AtomicLong(0); + private Type exceptionType = Type.GENERIC; + class Fail { private Fail() { @@ -51,10 +55,16 @@ class FailingDocumentStore extends Docum return this; } + Fail withType(Type type) { + exceptionType = type; + return this; + } + void never() { p = -1; numFailures.set(0); failAfter.set(Long.MAX_VALUE); + exceptionType = Type.GENERIC; } void once() { @@ -167,7 +177,7 @@ class FailingDocumentStore extends Docum private void maybeFail() { if (random.nextFloat() < p || failAfter.getAndDecrement() <= 0) { if (numFailures.getAndDecrement() > 0) { - throw new DocumentStoreException("write operation failed"); + throw new DocumentStoreException("write operation failed", null, exceptionType); } } }