Author: mreutegg
Date: Wed Oct  8 13:36:43 2014
New Revision: 1630100

URL: http://svn.apache.org/r1630100
Log:
OAK-2167: Last revision recover incomplete

Merge revisions 1630061 and 1630084 from trunk

Modified:
    jackrabbit/oak/branches/1.0/   (props changed)
    
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
    
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java
    
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java
    
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoMissingLastRevSeeker.java
    
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java

Propchange: jackrabbit/oak/branches/1.0/
------------------------------------------------------------------------------
  Merged /jackrabbit/oak/trunk:r1630061,1630084

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Wed Oct  8 13:36:43 2014
@@ -154,6 +154,12 @@ public final class DocumentNodeStore
     protected int asyncDelay = 1000;
 
     /**
+     * The maximum back off time in milliseconds when merges are retried. The
+     * default value is twice the {@link #asyncDelay}.
+     */
+    protected int maxBackOffMillis = asyncDelay * 2;
+
+    /**
      * Whether this instance is disposed.
      */
     private final AtomicBoolean isDisposed = new AtomicBoolean();
@@ -575,6 +581,14 @@ public final class DocumentNodeStore
         return asyncDelay;
     }
 
+    public void setMaxBackOffMillis(int time) {
+        maxBackOffMillis = time;
+    }
+
+    public int getMaxBackOffMillis() {
+        return maxBackOffMillis;
+    }
+
     @CheckForNull
     public ClusterNodeInfo getClusterInfo() {
         return clusterNodeInfo;

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 Wed Oct  8 13:36:43 2014
@@ -46,8 +46,8 @@ class DocumentNodeStoreBranch
                             DocumentNodeState base,
                             ReadWriteLock mergeLock) {
         super(store, new ChangeDispatcher(store.getRoot()), 
mergeLock.readLock(),
-                base, null, getMaxBackoffMillis(store),
-                getMaxBackoffMillis(store) * 3);
+                base, null, store.getMaxBackOffMillis(),
+                store.getMaxBackOffMillis() * 3);
         this.mergeLock = mergeLock;
     }
 
@@ -155,11 +155,6 @@ class DocumentNodeStoreBranch
 
     //------------------------------< internal 
>--------------------------------
 
-    private static long getMaxBackoffMillis(DocumentNodeStore store) {
-        // maximum back off is twice the async delay, but at least 2 seconds.
-        return Math.max(store.getAsyncDelay(), 1000) * 2;
-    }
-
     /**
      * Persist some changes on top of the given base state.
      *

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java
 Wed Oct  8 13:36:43 2014
@@ -97,14 +97,10 @@ public class LastRevRecoveryAgent {
                     startTime = leaseEnd - leaseTime - asyncDelay;
                 }
 
-                // Endtime is the leaseEnd + the asyncDelay
-                long endTime = leaseEnd + asyncDelay;
+                log.info("Recovering candidates modified after: [{}] for 
clusterId [{}]",
+                        Utils.timestampToString(startTime), clusterId);
 
-                log.info("Recovering candidates modified in time range : 
[{},{}] for clusterId [{}]",
-                        Utils.timestampToString(startTime),
-                        Utils.timestampToString(endTime), clusterId);
-
-                return recoverCandidates(clusterId, startTime, endTime);
+                return recoverCandidates(clusterId, startTime);
             }
         }
 
@@ -204,15 +200,14 @@ public class LastRevRecoveryAgent {
     }
 
     /**
-     * Retrieves possible candidates which have been modifed in the time range 
and recovers the
-     * missing updates.
+     * Retrieves possible candidates which have been modified after the given
+     * {@code startTime} and recovers the missing updates.
      * 
      * @param clusterId the cluster id
      * @param startTime the start time
-     * @param endTime the end time
      * @return the int the number of restored nodes
      */
-    private int recoverCandidates(final int clusterId, final long startTime, 
final long endTime) {
+    private int recoverCandidates(final int clusterId, final long startTime) {
         boolean lockAcquired = 
missingLastRevUtil.acquireRecoveryLock(clusterId);
 
         //TODO What if recovery is being performed for current clusterNode by 
some other node
@@ -223,7 +218,7 @@ public class LastRevRecoveryAgent {
             return 0;
         }
 
-        Iterable<NodeDocument> suspects = 
missingLastRevUtil.getCandidates(startTime, endTime);
+        Iterable<NodeDocument> suspects = 
missingLastRevUtil.getCandidates(startTime);
         log.debug("Performing Last Revision recovery for cluster {}", 
clusterId);
 
         try {

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java
 Wed Oct  8 13:36:43 2014
@@ -61,13 +61,13 @@ public class MissingLastRevSeeker {
     }
 
     /**
-     * Get the candidates with modified time between the time range specified.
+     * Get the candidates with modified time after the specified
+     * {@code startTime}.
      *
-     * @param startTime the start of the time range
-     * @param endTime the end of the time range
+     * @param startTime the start time.
      * @return the candidates
      */
-    public Iterable<NodeDocument> getCandidates(final long startTime, final 
long endTime) {
+    public Iterable<NodeDocument> getCandidates(final long startTime) {
         // Fetch all documents where lastmod >= startTime
         List<NodeDocument> nodes = store.query(Collection.NODES, 
NodeDocument.MIN_ID_VALUE,
                 NodeDocument.MAX_ID_VALUE, NodeDocument.MODIFIED_IN_SECS,  
NodeDocument.getModifiedInSecs(startTime), Integer.MAX_VALUE);
@@ -76,8 +76,7 @@ public class MissingLastRevSeeker {
             public boolean apply(NodeDocument input) {
                 Long modified = (Long) 
input.get(NodeDocument.MODIFIED_IN_SECS);
                 return (modified != null
-                        && (modified >= 
NodeDocument.getModifiedInSecs(startTime))
-                        && (modified <= 
NodeDocument.getModifiedInSecs(endTime)));
+                        && (modified >= 
NodeDocument.getModifiedInSecs(startTime)));
             }
         });
     }

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoMissingLastRevSeeker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoMissingLastRevSeeker.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoMissingLastRevSeeker.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoMissingLastRevSeeker.java
 Wed Oct  8 13:36:43 2014
@@ -53,12 +53,9 @@ public class MongoMissingLastRevSeeker e
     }
 
     @Override
-    public CloseableIterable<NodeDocument> getCandidates(final long startTime,
-            final long endTime) {
+    public CloseableIterable<NodeDocument> getCandidates(final long startTime) 
{
         DBObject query =
-                start(NodeDocument.MODIFIED_IN_SECS).lessThanEquals(
-                                NodeDocument.getModifiedInSecs(endTime))
-                        .put(NodeDocument.MODIFIED_IN_SECS).greaterThanEquals(
+                start(NodeDocument.MODIFIED_IN_SECS).greaterThanEquals(
                                 NodeDocument.getModifiedInSecs(startTime))
                         .get();
         DBObject sortFields = new BasicDBObject(NodeDocument.MODIFIED_IN_SECS, 
-1);

Modified: 
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java?rev=1630100&r1=1630099&r2=1630100&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java
 (original)
+++ 
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java
 Wed Oct  8 13:36:43 2014
@@ -23,7 +23,8 @@ import java.io.IOException;
 import java.util.List;
 
 import com.google.common.collect.Lists;
-import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -34,9 +35,12 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static 
org.apache.jackrabbit.oak.plugins.document.util.Utils.getIdFromPath;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 @RunWith(Parameterized.class)
 public class LastRevRecoveryAgentTest {
@@ -172,7 +176,54 @@ public class LastRevRecoveryAgentTest {
         assertFalse(ds1.getLastRevRecoveryAgent().isRecoveryNeeded());
     }
 
-    private NodeDocument getDocument(DocumentNodeStore nodeStore, String path) 
{
-        return nodeStore.getDocumentStore().find(Collection.NODES, 
Utils.getIdFromPath(path));
+    @Test
+    public void recoveryOfModifiedDocument() throws Exception {
+        // do not retry merges
+        ds1.setMaxBackOffMillis(0);
+        ds2.setMaxBackOffMillis(0);
+
+        NodeBuilder b1 = ds1.getRoot().builder();
+        b1.child("x").child("y").setProperty("p", "v1");
+        merge(ds1, b1);
+
+        ds1.runBackgroundOperations();
+        ds2.runBackgroundOperations();
+
+        NodeBuilder b2 = ds2.getRoot().builder();
+        b2.child("x").child("y").setProperty("p", "v2");
+        merge(ds2, b2);
+
+        // simulate a crash of ds2
+        long leaseTime = ds2.getClusterInfo().getLeaseTime();
+        clock.waitUntil(clock.getTime() + leaseTime * 2);
+
+        // this write will conflict because ds2 did not run
+        // background ops after setting p=v2
+        b1 = ds1.getRoot().builder();
+        b1.child("x").child("y").setProperty("p", "v11");
+        try {
+            merge(ds1, b1);
+            fail("CommitFailedException expected");
+        } catch (CommitFailedException e) {
+            // expected
+        }
+
+        ds1.getLastRevRecoveryAgent().recover(2);
+        ds1.runBackgroundOperations();
+
+        // now the write must succeed
+        b1 = ds1.getRoot().builder();
+        b1.child("x").child("y").setProperty("p", "v11");
+        merge(ds1, b1);
+    }
+
+    private static NodeDocument getDocument(DocumentNodeStore nodeStore,
+                                            String path) {
+        return nodeStore.getDocumentStore().find(NODES, getIdFromPath(path));
+    }
+
+    private static void merge(DocumentNodeStore store, NodeBuilder builder)
+            throws CommitFailedException {
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
     }
 }


Reply via email to