Author: mreutegg
Date: Tue Jul 25 14:19:59 2017
New Revision: 1802948

URL: http://svn.apache.org/viewvc?rev=1802948&view=rev
Log:
OAK-5602: Avoid missing journal entries

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1802948&r1=1802947&r2=1802948&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Tue Jul 25 14:19:59 2017
@@ -24,7 +24,9 @@ import static com.google.common.collect.
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Lists.reverse;
 import static java.util.Collections.singletonList;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.OAK;
 import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
 import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
 import static 
org.apache.jackrabbit.oak.plugins.document.Collection.CLUSTER_NODES;
@@ -1694,6 +1696,10 @@ public final class DocumentNodeStore
             UpdateOp op = new UpdateOp(Utils.getIdFromPath("/"), false);
             NodeDocument.setModified(op, commit.getRevision());
             if (b != null) {
+                // check the branch age and fail the commit
+                // if the first branch commit is too old
+                checkBranchAge(b);
+
                 commit.addBranchCommits(b);
                 Iterator<Revision> mergeCommits = 
commit.getMergeRevisions().iterator();
                 for (Revision rev : b.getCommits()) {
@@ -2718,11 +2724,14 @@ public final class DocumentNodeStore
         long minTimestamp = Utils.getMinTimestampForDiff(
                 from.getRootRevision(), to.getRootRevision(),
                 getMinExternalRevisions());
+        long minJournalTimestamp = newRevision().getTimestamp() -
+                journalGarbageCollector.getMaxRevisionAgeMillis() / 2;
 
         // use journal if possible
         Revision tailRev = journalGarbageCollector.getTailRevision();
         if (!disableJournalDiff
-                && tailRev.getTimestamp() < minTimestamp) {
+                && tailRev.getTimestamp() < minTimestamp
+                && minJournalTimestamp < minTimestamp) {
             diffAlgo = "diffJournalChildren";
             fromRev = from.getRootRevision();
             toRev = to.getRootRevision();
@@ -2912,6 +2921,22 @@ public final class DocumentNodeStore
         return System.currentTimeMillis();
     }
 
+    private void checkBranchAge(Branch b) throws CommitFailedException {
+        // check if initial branch commit is too old to merge
+        long journalMaxAge = journalGarbageCollector.getMaxRevisionAgeMillis();
+        long branchMaxAge = journalMaxAge / 2;
+        long created = b.getCommits().first().getTimestamp();
+        long branchAge = newRevision().getTimestamp() - created;
+        if (branchAge > branchMaxAge) {
+            String msg = "Long running commit detected. Branch was created " +
+                    Utils.timestampToString(created) + ". Consider breaking " +
+                    "the commit down into smaller pieces or increasing the " +
+                    "'journalGCMaxAge' currently set to " + journalMaxAge +
+                    " ms (" + MILLISECONDS.toMinutes(journalMaxAge) + " min).";
+            throw new CommitFailedException(OAK, 200, msg);
+        }
+    }
+
     /**
      * Creates and returns a MarkSweepGarbageCollector if the current BlobStore
      * supports garbage collection

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java?rev=1802948&r1=1802947&r2=1802948&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java
 Tue Jul 25 14:19:59 2017
@@ -77,11 +77,17 @@ public class JournalGarbageCollector {
      */
     public int gc() {
         DocumentStore ds = ns.getDocumentStore();
-        Revision keep = ns.getCheckpoints().getOldestRevisionToKeep();
+        Revision checkpointRev = ns.getCheckpoints().getOldestRevisionToKeep();
+        Long keep = null;
+        if (checkpointRev != null) {
+            // keep more entries than just up to the checkpoint to account
+            // for branch commits that may be referenced by merge commits
+            keep = checkpointRev.getTimestamp() - maxRevisionAgeMillis / 2;
+        }
         long now = ns.getClock().getTime();
         long gcOlderThan = now - maxRevisionAgeMillis;
-        if (keep != null && keep.getTimestamp() < gcOlderThan) {
-            gcOlderThan = keep.getTimestamp();
+        if (keep != null && keep < gcOlderThan) {
+            gcOlderThan = keep;
             log.debug("gc: Checkpoint {} is older than maxRevisionAge: {} min",
                     keep, MILLISECONDS.toMinutes(maxRevisionAgeMillis));
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1802948&r1=1802947&r2=1802948&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
 Tue Jul 25 14:19:59 2017
@@ -3320,7 +3320,6 @@ public class DocumentNodeStoreTest {
     }
 
     // OAK-5602
-    @Ignore("OAK-5602")
     @Test
     public void longRunningTx() throws Exception {
         Clock clock = new Clock.Virtual();
@@ -3375,7 +3374,6 @@ public class DocumentNodeStoreTest {
         after.compareAgainstBaseState(before, new DefaultNodeStateDiff());
     }
 
-    @Ignore("OAK-5602")
     @Test
     public void failLongRunningTx() throws Exception {
         Clock clock = new Clock.Virtual();

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java?rev=1802948&r1=1802947&r2=1802948&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java
 Tue Jul 25 14:19:59 2017
@@ -32,7 +32,6 @@ import org.apache.jackrabbit.oak.stats.C
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -116,7 +115,6 @@ public class JournalGCTest {
     }
 
     // OAK-5602
-    @Ignore("OAK-5602")
     @Test
     public void gcWithCheckpoint2() throws Exception {
         Clock c = new Clock.Virtual();


Reply via email to