You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2013/12/03 01:43:23 UTC

svn commit: r1547249 - /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java

Author: jukka
Date: Tue Dec  3 00:43:23 2013
New Revision: 1547249

URL: http://svn.apache.org/r1547249
Log:
OAK-593: Segment-based MK

Use a semaphore instead of custom synchronization helpers to control access ot the head state

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java?rev=1547249&r1=1547248&r2=1547249&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStore.java Tue Dec  3 00:43:23 2013
@@ -18,13 +18,13 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.concurrent.Semaphore;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
@@ -57,15 +57,11 @@ public class SegmentNodeStore implements
     volatile SegmentNodeState head;
 
     /**
-     * Whether a thread is currently processing a local commit.
+     * Semaphore that controls access to the {@link #head} variable.
+     * Only a single local commit is allowed at a time. When such
+     * a commit is in progress, no external updates will be seen.
      */
-    private boolean inLocalCommit = false;
-
-    /**
-     * Number of threads waiting to make a local commit.
-     * Used to avoid extra {@link #notifyAll()} calls when nobody is waiting.
-     */
-    private long waitingToCommit = 0;
+    private final Semaphore commitSemaphore = new Semaphore(1);
 
     private long maximumBackoff = MILLISECONDS.convert(10, SECONDS);
 
@@ -88,62 +84,32 @@ public class SegmentNodeStore implements
     /**
      * Refreshes the head state. Does nothing if a concurrent local commit is
      * in progress, as that commit will automatically refresh the head state.
-     *
-     * @param commit whether this refresh is a part of a local commit
      */
-    private synchronized void refreshHead(boolean commit) {
-        if (commit || !inLocalCommit) {
-            RecordId id = journal.getHead();
-            if (!id.equals(head.getRecordId())) {
-                head = new SegmentNodeState(
-                        store.getWriter().getDummySegment(), id);
-                changeDispatcher.contentChanged(head.getChildNode(ROOT), null);
-            }
-        }
-    }
-
-    private synchronized void refreshHeadInCommit(boolean start)
-            throws InterruptedException {
-        if (start) {
-            while (inLocalCommit) {
-                waitingToCommit++;
-                try {
-                    wait();
-                } finally {
-                    waitingToCommit--;
-                }
-            }
-            inLocalCommit = true;
-        } else {
-            checkState(inLocalCommit);
-        }
-
-        try {
-            refreshHead(true);
-        } finally {
-            if (!start) {
-                inLocalCommit = false;
-                if (waitingToCommit > 0) {
-                    notifyAll();
-                }
-            }
+    private void refreshHead() {
+        RecordId id = journal.getHead();
+        if (!id.equals(head.getRecordId())) {
+            head = new SegmentNodeState(
+                    store.getWriter().getDummySegment(), id);
+            changeDispatcher.contentChanged(head.getChildNode(ROOT), null);
         }
     }
 
     boolean setHead(
             SegmentNodeState base, SegmentNodeState head, CommitInfo info)
             throws InterruptedException {
-        refreshHeadInCommit(true);
+        commitSemaphore.acquire();
         try {
+            refreshHead();
             if (journal.setHead(base.getRecordId(), head.getRecordId())) {
                 this.head = head;
                 changeDispatcher.contentChanged(head.getChildNode(ROOT), info);
+                refreshHead();
                 return true;
             } else {
                 return false;
             }
         } finally {
-            refreshHeadInCommit(false);
+            commitSemaphore.release();
         }
     }
 
@@ -154,7 +120,13 @@ public class SegmentNodeStore implements
 
     @Override @Nonnull
     public NodeState getRoot() {
-        refreshHead(false);
+        if (commitSemaphore.tryAcquire()) {
+            try {
+                refreshHead();
+            } finally {
+                commitSemaphore.release();
+            }
+        }
         return new SegmentRootState(head);
     }