Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 88838 invoked from network); 19 Dec 2007 09:43:57 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 19 Dec 2007 09:43:57 -0000 Received: (qmail 84669 invoked by uid 500); 19 Dec 2007 09:43:47 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 84580 invoked by uid 500); 19 Dec 2007 09:43:46 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 84570 invoked by uid 99); 19 Dec 2007 09:43:46 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 19 Dec 2007 01:43:46 -0800 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 19 Dec 2007 09:43:32 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 4249A1A984E; Wed, 19 Dec 2007 01:43:36 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@jackrabbit.apache.org From: mreutegg@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20071219094336.4249A1A984E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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; + +/** + * AbstractISMLockingTest 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: + *

+ * While a read lock is held for a given item with id I an + * implementation must ensure that no write lock is issued for a change log + * that contains a reference to an item with id 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: + *

+ * While a write lock is held for a given change log C an + * implementation must ensure that no read lock is issued for an item that + * is contained in C, unless the current thread is the owner of + * the write lock! + */ + 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: + *

+ * While a write lock is held for a given change log C an + * implementation must ensure that no write lock is issued for a change log + * C' that intersects with C. 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; + +/** + * DefaultISMLockingTest 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; + +/** + * FineGrainedISMLockingTest 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; }