jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r605488 - in /jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state: AbstractISMLockingTest.java DefaultISMLockingTest.java FineGrainedISMLockingTest.java TestAll.java
Date Wed, 19 Dec 2007 09:43:35 GMT
Author: mreutegg
Date: Wed Dec 19 01:43:34 2007
New Revision: 605488

URL: http://svn.apache.org/viewvc?rev=605488&view=rev
Log:
JCR-314: Fine grained locking in SharedItemStateManager
- test cases

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java
  (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java
  (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/TestAll.java

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java?rev=605488&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java
Wed Dec 19 01:43:34 2007
@@ -0,0 +1,314 @@
+/*
+ * 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.state;
+
+import junit.framework.TestCase;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.ItemId;
+import org.apache.jackrabbit.uuid.UUID;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * <code>AbstractISMLockingTest</code> contains test cases for the ISMLocking
+ * requirements.
+ */
+public abstract class AbstractISMLockingTest extends TestCase {
+
+    protected ISMLocking locking;
+
+    /**
+     * Test node state.
+     */
+    protected NodeState state;
+
+    /**
+     * Node references instance targeting {@link #state}.
+     */
+    protected NodeReferences refs;
+
+    /**
+     * List of change logs, each with a different modification for {@link #state}.
+     */
+    protected List logs;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        locking = createISMLocking();
+        NodeId id = new NodeId(UUID.randomUUID());
+        state = new NodeState(id, NameConstants.NT_BASE, null, ItemState.STATUS_EXISTING,
true);
+        refs = new NodeReferences(new NodeReferencesId(state.getNodeId()));
+        logs = new ArrayList();
+        ChangeLog log = new ChangeLog();
+        log.added(state);
+        logs.add(log);
+        log = new ChangeLog();
+        log.deleted(state);
+        logs.add(log);
+        log = new ChangeLog();
+        log.modified(state);
+        logs.add(log);
+        log = new ChangeLog();
+        log.modified(refs);
+        logs.add(log);
+    }
+
+    /**
+     * Checks the following requirement:
+     * <p/>
+     * <i>While a read lock is held for a given item with id <code>I</code>
an
+     * implementation must ensure that no write lock is issued for a change log
+     * that contains a reference to an item with id <code>I</code>. </i>
+     */
+    public void testReadBlocksWrite() throws InterruptedException {
+        ISMLocking.ReadLock rLock = locking.acquireReadLock(state.getId());
+        try {
+            for (Iterator it = logs.iterator(); it.hasNext(); ) {
+                final ChangeLog log = (ChangeLog) it.next();
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            checkBlocking(log);
+                        } catch (InterruptedException e) {
+                            fail(e.toString());
+                        }
+                    }
+                });
+                t.start();
+                t.join();
+            }
+        } finally {
+            rLock.release();
+        }
+    }
+
+    /**
+     * Checks the following requirement:
+     * <p/>
+     * <i>While a write lock is held for a given change log <code>C</code>
an
+     * implementation must ensure that no read lock is issued for an item that
+     * is contained in <code>C</code>, unless the current thread is the owner
of
+     * the write lock!</i>
+     */
+    public void testWriteBlocksRead() throws InterruptedException {
+        for (Iterator it = logs.iterator(); it.hasNext(); ) {
+            ISMLocking.WriteLock wLock
+                    = locking.acquireWriteLock((ChangeLog) it.next());
+            try {
+                checkNonBlocking(state.getId());
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            checkBlocking(state.getId());
+                        } catch (InterruptedException e) {
+                            fail(e.toString());
+                        }
+                    }
+                });
+                t.start();
+                t.join();
+            } finally {
+                wLock.release();
+            }
+        }
+    }
+
+    /**
+     * Checks the following requirement:
+     * <p/>
+     * While a write lock is held for a given change log <code>C</code> an
+     * implementation must ensure that no write lock is issued for a change log
+     * <code>C'</code> that intersects with <code>C</code>. That
is both change
+     * logs contain a reference to the same item. Please note that an
+     * implementation is free to block requests entirely for additional write
+     * lock while a write lock is active. It is not a requirement to support
+     * concurrent write locks.
+     */
+    public void testIntersectingWrites() throws InterruptedException {
+        ChangeLog cl = new ChangeLog();
+        cl.added(state);
+        ISMLocking.WriteLock wLock = locking.acquireWriteLock(cl);
+        try {
+            for (Iterator it = logs.iterator(); it.hasNext(); ) {
+                final ChangeLog log = (ChangeLog) it.next();
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            checkBlocking(log);
+                        } catch (InterruptedException e) {
+                            fail(e.toString());
+                        }
+                    }
+                });
+                t.start();
+                t.join();
+            }
+        } finally {
+            wLock.release();
+        }
+    }
+
+    /**
+     * Checks if a downgraded write lock allows other threads to read again.
+     */
+    public void testDowngrade() throws InterruptedException {
+        for (Iterator it = logs.iterator(); it.hasNext(); ) {
+            ISMLocking.ReadLock rLock = locking.acquireWriteLock(
+                    (ChangeLog) it.next()).downgrade();
+            try {
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            checkNonBlocking(state.getId());
+                        } catch (InterruptedException e) {
+                            fail(e.toString());
+                        }
+                    }
+                });
+                t.start();
+                t.join();
+            } finally {
+                rLock.release();
+            }
+        }
+    }
+
+    //------------------------------< utilities >-------------------------------
+
+    protected void checkBlocking(ChangeLog log)
+            throws InterruptedException {
+        final Thread t = Thread.currentThread();
+        TimeBomb tb = new TimeBomb(100) {
+            public void explode() {
+                t.interrupt();
+            }
+        };
+        tb.arm();
+        try {
+            locking.acquireWriteLock(log).release();
+        } catch (InterruptedException e) {
+            // success
+            return;
+        }
+        tb.disarm();
+        // make sure interrupted status is cleared
+        // bomb may blow off right before we disarm it
+        Thread.interrupted();
+        fail("acquireWriteLock must block");
+    }
+
+    protected void checkBlocking(ItemId id)
+            throws InterruptedException {
+        final Thread t = Thread.currentThread();
+        TimeBomb tb = new TimeBomb(100) {
+            public void explode() {
+                t.interrupt();
+            }
+        };
+        tb.arm();
+        try {
+            locking.acquireReadLock(id).release();
+        } catch (InterruptedException e) {
+            // success
+            return;
+        }
+        tb.disarm();
+        // make sure interrupted status is cleared
+        // bomb may blow off right before we disarm it
+        Thread.interrupted();
+        fail("acquireReadLock must block");
+    }
+
+    protected void checkNonBlocking(ItemId id)
+            throws InterruptedException {
+        final Thread t = Thread.currentThread();
+        TimeBomb tb = new TimeBomb(100) {
+            public void explode() {
+                t.interrupt();
+            }
+        };
+        tb.arm();
+        try {
+            locking.acquireReadLock(id).release();
+        } catch (InterruptedException e) {
+            fail("acquireReadLock must not block");
+        }
+        tb.disarm();
+        // make sure interrupted status is cleared
+        // bomb may blow off right before we disarm it
+        Thread.interrupted();
+    }
+
+    public abstract ISMLocking createISMLocking();
+
+    protected static abstract class TimeBomb {
+
+        private final boolean[] armed = {false};
+
+        private final long millis;
+
+        private Thread timer;
+
+        public TimeBomb(long millis) {
+            this.millis = millis;
+        }
+
+        public void arm() throws InterruptedException {
+            synchronized (armed) {
+                if (armed[0]) {
+                    return;
+                } else {
+                    timer = new Thread(new Runnable() {
+                        public void run() {
+                            synchronized (armed) {
+                                armed[0] = true;
+                                armed.notify();
+                            }
+                            try {
+                                Thread.sleep(millis);
+                                explode();
+                            } catch (InterruptedException e) {
+                                // disarmed
+                            }
+                        }
+                    });
+                    timer.start();
+                }
+            }
+            synchronized (armed) {
+                while (!armed[0]) {
+                    armed.wait();
+                }
+            }
+        }
+
+        public void disarm() throws InterruptedException {
+            synchronized (armed) {
+                if (!armed[0]) {
+                    return;
+                }
+            }
+            timer.interrupt();
+            timer.join();
+        }
+
+        public abstract void explode();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/AbstractISMLockingTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java?rev=605488&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java
Wed Dec 19 01:43:34 2007
@@ -0,0 +1,28 @@
+/*
+ * 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.state;
+
+/**
+ * <code>DefaultISMLockingTest</code> executes the test cases implemented in
+ * {@link AbstractISMLockingTest}.
+ */
+public class DefaultISMLockingTest extends AbstractISMLockingTest {
+
+    public ISMLocking createISMLocking() {
+        return new DefaultISMLocking();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/DefaultISMLockingTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java?rev=605488&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java
Wed Dec 19 01:43:34 2007
@@ -0,0 +1,28 @@
+/*
+ * 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.state;
+
+/**
+ * <code>FineGrainedISMLockingTest</code> executes the test cases implemented
in
+ * {@link AbstractISMLockingTest}.
+ */
+public class FineGrainedISMLockingTest extends AbstractISMLockingTest {
+
+    public ISMLocking createISMLocking() {
+        return new FineGrainedISMLocking();
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/FineGrainedISMLockingTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/TestAll.java?rev=605488&r1=605487&r2=605488&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/TestAll.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/state/TestAll.java
Wed Dec 19 01:43:34 2007
@@ -36,6 +36,8 @@
         TestSuite suite = new TestSuite("State tests");
 
         suite.addTestSuite(ChangeLogTest.class);
+        suite.addTestSuite(DefaultISMLockingTest.class);
+        suite.addTestSuite(FineGrainedISMLockingTest.class);
 
         return suite;
     }



Mime
View raw message