Index: src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/state/FineGrainedISMLocking.java (revision 0) @@ -0,0 +1,186 @@ +/* + * 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 org.apache.jackrabbit.core.ItemId; +import org.apache.jackrabbit.core.NodeId; + +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +/** + * FineGrainedISMLocking... + */ +public class FineGrainedISMLocking implements ISMLocking { + + /** + * Avoid creating commonly used Integer instances. + */ + private static final Integer ONE = new Integer(1); + + /** + * An anonymous read lock without an id assigned. + */ + private final ReadLock ANONYMOUS_READ_LOCK = new ReadLockImpl(); + + /** + * The active writer or null if there is none. + */ + private WriteLockImpl activeWriter; + + /** + * Maps ItemId to the number of read locks currently held. + */ + private final Map readLocks = new HashMap(); + + /** + * {@inheritDoc} + */ + public ReadLock acquireReadLock(ItemId id) + throws InterruptedException { + synchronized (readLocks) { + for (;;) { + // check if there is an active writer + if (activeWriter != null) { + if (hasDependency(activeWriter.changes, id) && + activeWriter.thread != Thread.currentThread()) { + // wait and try again + readLocks.wait(); + continue; + } + } + // if we get here, there is no active writer or there is + // no dependency to the change log of the active writer + Integer numReaders = (Integer) readLocks.get(id); + if (numReaders == null) { + readLocks.put(id, ONE); + } else { + readLocks.put(id, new Integer(numReaders.intValue() + 1)); + } + return new ReadLockImpl(id); + } + } + } + + /** + * {@inheritDoc} + */ + public WriteLock acquireWriteLock(ChangeLog changeLog) + throws InterruptedException { + synchronized (readLocks) { + for (;;) { + if (activeWriter != null) { + // wait and try again + readLocks.wait(); + continue; + } else { + // check read locks + if (readLocks.size() != 0) { + boolean conflicting = false; + for (Iterator it = readLocks.keySet().iterator(); it.hasNext(); ) { + ItemId id = (ItemId) it.next(); + if (id != null) { + if (hasDependency(changeLog, id)) { + conflicting = true; + break; + } + } else { + // this is a downgraded write lock + conflicting = true; + break; + } + } + if (conflicting) { + // have to wait and try again + readLocks.wait(); + continue; + } + } + // if we get here we are allowed to issue a write lock + activeWriter = new WriteLockImpl(changeLog); + return activeWriter; + } + } + } + } + + //----------------------------< internal >---------------------------------- + + private final class WriteLockImpl implements WriteLock { + + private final ChangeLog changes; + + private final Thread thread; + + WriteLockImpl(ChangeLog changes) { + this.changes = changes; + this.thread = Thread.currentThread(); + } + + public void release() { + synchronized (readLocks) { + activeWriter = null; + readLocks.notifyAll(); + } + } + + public ReadLock downgrade() { + synchronized (readLocks) { + activeWriter = null; + readLocks.put(null, ONE); + readLocks.notifyAll(); + } + return ANONYMOUS_READ_LOCK; + } + + } + + private final class ReadLockImpl implements ReadLock { + + private final ItemId id; + + public ReadLockImpl() { + this(null); + } + + ReadLockImpl(ItemId id) { + this.id = id; + } + + public void release() { + synchronized (readLocks) { + readLocks.remove(id); + readLocks.notifyAll(); + } + } + } + + private boolean hasDependency(ChangeLog changeLog, ItemId id) { + try { + if (changeLog.get(id) == null) { + if (!id.denotesNode() || changeLog.get(new NodeReferencesId((NodeId) id)) == null) { + // change log does not contain the item + return false; + } + } + } catch (NoSuchItemStateException e) { + // is deleted + } + return true; + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\state\FineGrainedISMLocking.java ___________________________________________________________________ Name: svn:eol-style + native