Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java (revision 1601549) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java (working copy) @@ -94,6 +94,7 @@ public void releaseRecoveryLock(int clusterId){ UpdateOp update = new UpdateOp(Integer.toString(clusterId), true); update.set(ClusterNodeInfo.REV_RECOVERY_LOCK, null); + update.set(ClusterNodeInfo.STATE, null); store.createOrUpdate(Collection.CLUSTER_NODES, update); } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java (revision 1601549) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgentTest.java (working copy) @@ -35,6 +35,7 @@ import org.junit.runners.Parameterized; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(Parameterized.class) @@ -140,6 +141,37 @@ assertEquals(zlastRev2, getDocument(ds1, "/").getLastRev().get(c2Id)); } + @Test + public void testRepeatedRecovery() throws Exception { + //1. Create base structure /x/y + NodeBuilder b1 = ds1.getRoot().builder(); + b1.child("x").child("y"); + ds1.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY); + ds1.runBackgroundOperations(); + + ds2.runBackgroundOperations(); + + //2. Add a new node /x/y/z in C2 + NodeBuilder b2 = ds2.getRoot().builder(); + b2.child("x").child("y").child("z").setProperty("foo", "bar"); + ds2.merge(b2, EmptyHook.INSTANCE, CommitInfo.EMPTY); + + NodeDocument z1 = getDocument(ds1, "/x/y/z"); + Revision zlastRev2 = z1.getLastRev().get(c2Id); + + long leaseTime = ds1.getClusterInfo().getLeaseTime(); + ds1.runBackgroundOperations(); + + clock.waitUntil(clock.getTime() + leaseTime + 10); + + //Renew the lease for C1 + ds1.getClusterInfo().renewLease(); + + assertTrue(ds1.getLastRevRecoveryAgent().isRecoveryNeeded()); + ds1.getLastRevRecoveryAgent().performRecoveryIfNeeded(); + assertFalse(ds1.getLastRevRecoveryAgent().isRecoveryNeeded()); + } + private NodeDocument getDocument(DocumentNodeStore nodeStore, String path) { return nodeStore.getDocumentStore().find(Collection.NODES, Utils.getIdFromPath(path)); }