You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2009/12/10 15:08:33 UTC

svn commit: r889270 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/util/ test/java/org/apache/jackrabbit/core/util/

Author: thomasm
Date: Thu Dec 10 14:08:32 2009
New Revision: 889270

URL: http://svn.apache.org/viewvc?rev=889270&view=rev
Log:
JCR-2431 CooperativeFileLock improvements

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/CooperativeFileLockTest.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java?rev=889270&r1=889269&r2=889270&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/CooperativeFileLock.java Thu Dec 10 14:08:32 2009
@@ -31,11 +31,11 @@
 import javax.jcr.RepositoryException;
 
 /**
- * The file lock is used to ensure a resource is only open once at any time. 
- * It uses a cooperative locking protocol. 
+ * The file lock is used to ensure a resource is only open once at any time.
+ * It uses a cooperative locking protocol.
  */
 public class CooperativeFileLock implements RepositoryLockMechanism {
-    
+
     /**
      * Logger instance.
      */
@@ -55,9 +55,11 @@
     private boolean locked;
     private volatile boolean stop;
 
+    private Thread watchdog;
+
     /**
      * Create a new file locking object using the given file name.
-     * 
+     *
      * @param path basic path to append {@link #FILE_NAME} to.
      */
     public void init(String path) {
@@ -68,7 +70,7 @@
      * Lock the directory if possible.
      * This method will also start a background watchdog thread.
      * A file may only be locked once.
-     * 
+     *
      * @throws RepositoryException if locking was not successful
      */
     public synchronized void acquire() throws RepositoryException {
@@ -97,17 +99,16 @@
             }
         } catch (Exception e) {
             LOG.warn("Error unlocking " + fileName, e);
+        } finally {
+            stop = true;
+            locked = false;
         }
-        stop = true;
-        locked = false;
-    }
-
-    /**
-     * This finalizer unlocks the file if necessary.
-     */
-    protected void finalize() {
-        if (locked) {
-            release();
+        try {
+            if (watchdog != null) {
+                watchdog.interrupt();
+            }
+        } catch (Exception e) {
+            LOG.debug("Error stopping watchdog " + fileName, e);
         }
     }
 
@@ -133,7 +134,7 @@
 
     /**
      * Load the properties file.
-     * 
+     *
      * @return the properties object
      */
     private Properties load() throws RepositoryException {
@@ -163,7 +164,14 @@
             long last = f.lastModified();
             long dist = System.currentTimeMillis() - last;
             if (dist < -TIME_GRANULARITY) {
-                throw error("Lock file modified in the future: dist=" + dist);
+                // lock file modified in the future -
+                // wait for a bit longer than usual
+                try {
+                    Thread.sleep(2 * LOCK_SLEEP);
+                } catch (Exception e) {
+                    LOG.debug("Sleep", e);
+                }
+                return;
             } else if (dist > TIME_GRANULARITY) {
                 return;
             }
@@ -186,9 +194,12 @@
         if (!createNewFile(fileName)) {
             waitUntilOld();
             save();
-            sleep(2 * LOCK_SLEEP);
-            if (!load().equals(properties)) {
-                throw error("Locked by another process");
+            // wait twice the watchdog sleep time
+            for (int i = 0; i < 8; i++) {
+                sleep(LOCK_SLEEP / 4);
+                if (!load().equals(properties)) {
+                    throw error("Locked by another process");
+                }
             }
             delete(fileName);
             if (!createNewFile(fileName)) {
@@ -201,7 +212,7 @@
             stop = true;
             throw error("Concurrent update");
         }
-        Thread watchdog = new Thread(new Runnable() {
+        watchdog = new Thread(new Runnable() {
             public void run() {
                 try {
                     while (!stop) {
@@ -212,6 +223,12 @@
                                 save();
                             }
                             Thread.sleep(LOCK_SLEEP);
+                        } catch (OutOfMemoryError e) {
+                            // ignore
+                        } catch (InterruptedException e) {
+                            // ignore
+                        } catch (NullPointerException e) {
+                            // ignore
                         } catch (Exception e) {
                             LOG.debug("Watchdog", e);
                         }
@@ -243,11 +260,11 @@
             throw getException(e);
         }
     }
-    
+
     /**
      * Create a new file, and retry if this doesn't work.
      * If it still doesn't work after some time, this method returns false.
-     * 
+     *
      * @param fileName the name of the file to create
      * @return if the file was created
      */
@@ -263,11 +280,11 @@
         }
         return false;
     }
-    
+
     /**
      * Delete a file, and retry if this doesn't work.
      * If it still doesn't work after some time, an exception is thrown.
-     * 
+     *
      * @param fileName the name of the file to delete
      * @throws RepositoryException if the file could not be deleted
      */
@@ -286,8 +303,8 @@
             }
             throw new RepositoryException("Could not delete file " + fileName);
         }
-    }    
-    
+    }
+
     private static void wait(int i) {
         if (i > 8) {
             System.gc();

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/CooperativeFileLockTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/CooperativeFileLockTest.java?rev=889270&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/CooperativeFileLockTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/CooperativeFileLockTest.java Thu Dec 10 14:08:32 2009
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Tests the cooperative file lock mechanism.
+ */
+public class CooperativeFileLockTest extends TestCase {
+
+    private static final String TEST_DIRECTORY = "target/tmp/testCooperativeFileLock";
+
+    public void tearDown() throws IOException {
+        setUp();
+    }
+
+    public void setUp() throws IOException {
+        FileUtils.deleteDirectory(new File(TEST_DIRECTORY));
+    }
+
+    public void testFileLock() throws RepositoryException {
+        int testRuns = 1;
+        for (int i = 0; i < testRuns; i++) {
+            new File(TEST_DIRECTORY).mkdirs();
+            CooperativeFileLock l1 = new CooperativeFileLock();
+            l1.init(TEST_DIRECTORY);
+            l1.acquire();
+            CooperativeFileLock l2 = new CooperativeFileLock();
+            l2.init(TEST_DIRECTORY);
+            try {
+                l2.acquire();
+                fail();
+            } catch (Exception e) {
+                // expected
+            }
+            l1.release();
+            l2.acquire();
+            l2.release();
+        }
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java?rev=889270&r1=889269&r2=889270&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/TestAll.java Thu Dec 10 14:08:32 2009
@@ -33,6 +33,7 @@
     public static Test suite() {
         TestSuite suite = new TestSuite("Utility tests");
         suite.addTestSuite(RepositoryLockTest.class);
+        suite.addTestSuite(CooperativeFileLockTest.class);
         return suite;
     }
 }