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