Index: src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java (revision 1400501) +++ src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java (working copy) @@ -135,7 +135,7 @@ if (!ism.hasItemState(id)) { NodeImpl p = (NodeImpl) itemMgr.getItem(parentId); p.removeChildNode((NodeId) id); - p.save(); + new AutoFixSaveThread(p).start(); } } catch (RepositoryException e2) { log.error("could not fix repository inconsistency", e); @@ -266,4 +266,26 @@ public void remove() { throw new UnsupportedOperationException("remove"); } + + /** + * The autofix save thread + */ + static class AutoFixSaveThread extends Thread { + private final NodeImpl n; + + AutoFixSaveThread(NodeImpl n) { + super("AutoFix-Thread"); + this.n = n; + } + + @Override + public void run() { + try { + n.save(); + } catch (RepositoryException e) { + log.error("could not fix repository inconsistency", e); + // ignore + } + } + } } Index: src/main/java/org/apache/jackrabbit/core/session/SessionState.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/session/SessionState.java (revision 1400501) +++ src/main/java/org/apache/jackrabbit/core/session/SessionState.java (working copy) @@ -19,8 +19,7 @@ import static org.apache.jackrabbit.api.stats.RepositoryStatistics.Type; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -90,7 +89,7 @@ * synchronization in order to be able to log attempts to concurrently * use a session. */ - private final Lock lock = new ReentrantLock(); + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); /** * Flag to indicate that the current operation is a write operation. @@ -167,12 +166,9 @@ throws RepositoryException { String session = context.getSessionImpl().toString(); - // Acquire the exclusive lock for accessing session internals. - // No other session should be holding the lock, so we log a - // message to let the user know of such cases. - if (!lock.tryLock()) { - if (isWriteOperation - && operation instanceof SessionWriteOperation) { + boolean isSessionWriteOperation = operation instanceof SessionWriteOperation; + if (isSessionWriteOperation || lock.writeLock().isHeldByCurrentThread()) { + if (!lock.writeLock().tryLock()) { Exception trace = new Exception( "Stack trace of concurrent access to " + session); log.warn("Attempt to perform " + operation @@ -181,17 +177,19 @@ + " thread is finished using this session. Please" + " review your code to avoid concurrent use of" + " a session.", trace); - } else if (log.isDebugEnabled()) { + lock.writeLock().lock(); + } + } else { + if (log.isDebugEnabled() && (lock.isWriteLocked() || lock.getReadHoldCount() < lock.getReadLockCount() )) { Exception trace = new Exception( "Stack trace of concurrent access to " + session); log.debug("Attempt to perform " + operation + " while" + " another thread is concurrently reading from " - + session + ". Blocking until the other thread" - + " is finished using this session. Please" - + " review your code to avoid concurrent use of" - + " a session.", trace); + + session + ". Obtaining another read lock for this" + + "session. Please review your code to avoid" + + " concurrent use of a session.", trace); } - lock.lock(); + lock.readLock().lock(); } boolean isOutermostWriteOperation = false; @@ -202,8 +200,7 @@ // Raise the isWriteOperation flag for write operations. // The flag is used to set the appropriate log level above. boolean wasWriteOperation = isWriteOperation; - if (!wasWriteOperation - && operation instanceof SessionWriteOperation) { + if (!wasWriteOperation && isSessionWriteOperation) { isWriteOperation = true; isOutermostWriteOperation = true; } @@ -232,7 +229,11 @@ isWriteOperation = wasWriteOperation; } } finally { - lock.unlock(); + if(isSessionWriteOperation || lock.writeLock().isHeldByCurrentThread()) { + lock.writeLock().unlock(); + } else { + lock.readLock().unlock(); + } // Delay return from a write operation if the observation queue // is being overloaded. This needs to be done after releasing @@ -259,7 +260,7 @@ public boolean close() { String session = context.getSessionImpl().toString(); - if (!lock.tryLock()) { + if (!lock.writeLock().tryLock()) { Exception trace = new Exception( "Stack trace of concurrent access to " + session); log.warn("Attempt to close " + session + " while another" @@ -267,7 +268,7 @@ + " Blocking until the other thread is finished" + " using this session. Please review your code" + " to avoid concurrent use of a session.", trace); - lock.lock(); + lock.writeLock().lock(); } try { if (isAlive()) { @@ -289,7 +290,7 @@ return false; } } finally { - lock.unlock(); + lock.writeLock().unlock(); } } Index: src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java (revision 1400501) +++ src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java (working copy) @@ -138,7 +138,7 @@ * @return session operation */ public static SessionItemOperation remove(String path) { - return new SessionItemOperation("remove", path) { + return new SessionItemRemoveOperation("remove", path) { @Override @SuppressWarnings("deprecation") protected Object perform(ItemManager manager, Path path) throws RepositoryException { @@ -215,4 +215,14 @@ public String toString() { return method + "(" + path + ")"; } -} \ No newline at end of file + + private static abstract class SessionItemRemoveOperation extends + SessionItemOperation implements + SessionWriteOperation { + + SessionItemRemoveOperation(String method, String path) { + super(method, path); + } + } + +}