### Eclipse Workspace Patch 1.0 #P jackrabbit-core Index: src/main/java/org/apache/jackrabbit/core/TransactionContext.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/TransactionContext.java (revision 705186) +++ src/main/java/org/apache/jackrabbit/core/TransactionContext.java (working copy) @@ -21,6 +21,9 @@ import org.apache.jackrabbit.util.Timer; import javax.transaction.xa.XAException; +import javax.transaction.xa.Xid; + +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -47,6 +50,11 @@ private static final int STATUS_ROLLED_BACK = 6; /** + * The per thread associated Xid + */ + private static ThreadLocal CURRENT_XID = new ThreadLocal(); + + /** * Create a global timer for all transaction contexts. */ private static final Timer TIMER = new Timer(true); @@ -62,6 +70,11 @@ private final int timeout; /** + * The Xid + */ + private final Xid xid; + + /** * Transaction attributes. */ private final Map attributes = new HashMap(); @@ -78,10 +91,12 @@ /** * Create a new instance of this class. + * @param xid associated xid * @param resources transactional resources * @param timeout timeout, in seconds */ - public TransactionContext(InternalXAResource[] resources, int timeout) { + public TransactionContext(Xid xid, InternalXAResource[] resources, int timeout) { + this.xid = xid; this.resources = resources; this.timeout = timeout; } @@ -129,6 +144,7 @@ * @throws XAException if an error occurs */ public synchronized void prepare() throws XAException { + bindCurrentXid(); status = STATUS_PREPARING; beforeOperation(); @@ -172,6 +188,7 @@ if (status == STATUS_ROLLED_BACK) { throw new XAException(XAException.XA_RBTIMEOUT); } + bindCurrentXid(); status = STATUS_COMMITTING; beforeOperation(); @@ -197,6 +214,7 @@ // cancel the rollback task cancel(); + cleanCurrentXid(); if (txe != null) { XAException e = new XAException(XAException.XA_RBOTHER); @@ -214,6 +232,7 @@ if (status == STATUS_ROLLED_BACK) { throw new XAException(XAException.XA_RBTIMEOUT); } + bindCurrentXid(); status = STATUS_ROLLING_BACK; beforeOperation(); @@ -232,6 +251,7 @@ // cancel the rollback task cancel(); + cleanCurrentXid(); if (errors != 0) { throw new XAException(XAException.XA_RBOTHER); @@ -295,4 +315,42 @@ public void setSuspended(boolean suspended) { this.suspended = suspended; } + + /** + * Helper Method to bind the {@link Xid} associated with this {@link TransactionContext} + * to the {@link #CURRENT_XID} ThreadLocal + * @param methodName + */ + private void bindCurrentXid() { + CURRENT_XID.set(xid); + } + + /** + * Helper Method to clean the {@link Xid} associated with this {@link TransactionContext} + * from the {@link #CURRENT_XID} ThreadLocal + * @param methodName + */ + private void cleanCurrentXid() { + CURRENT_XID.set(null); + } + + /** + * Returns the {@link Xid} bind to the {@link #CURRENT_XID} ThreadLocal + * @return current Xid or null + */ + public static Xid getCurrentXid() { + return (Xid) CURRENT_XID.get(); + } + + /** + * Helper Method to check if the given {@link Xid} has the same globalTransactionId + * as the current {@link Xid} bind to the {@link #CURRENT_XID} ThreadLocal + * @param xid Xid to check + * @param primary this boolean has the primary priority. this means if it is true no check will be performed + * @return same or not + */ + public static boolean isCurrentXid(Xid xid, boolean primary) { + Xid currentXid = (Xid) CURRENT_XID.get(); + return primary ? true : (currentXid == null | xid == null) ? primary : Arrays.equals(xid.getGlobalTransactionId(), currentXid.getGlobalTransactionId()); + } } Index: src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (revision 705186) +++ src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (working copy) @@ -25,6 +25,7 @@ import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.SessionListener; +import org.apache.jackrabbit.core.TransactionContext; import org.apache.jackrabbit.core.cluster.ClusterOperation; import org.apache.jackrabbit.core.cluster.LockEventChannel; import org.apache.jackrabbit.core.cluster.LockEventListener; @@ -49,6 +50,8 @@ import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; +import javax.transaction.xa.Xid; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -79,11 +82,45 @@ */ private final PathMap lockMap = new PathMap(); - /** - * Lock to path map. - */ - private final ReentrantLock lockMapLock = new ReentrantLock(); + private final ReentrantLock lockMapLock = new ReentrantLock(){ + + private Xid activeXid; + + public void acquire() throws InterruptedException { + if (Thread.interrupted()) throw new InterruptedException(); + Thread caller = Thread.currentThread(); + synchronized(this) { + boolean allow = TransactionContext.isCurrentXid(activeXid, caller == owner_); + if (allow) { + ++holds_; + } else { + try { + while (owner_ != null) + wait(); + owner_ = caller; + activeXid = (Xid) TransactionContext.getCurrentXid(); + holds_ = 1; + } catch (InterruptedException ex) { + notify(); + throw ex; + } + } + } + } + + public synchronized void release() { + boolean allow = TransactionContext.isCurrentXid(activeXid, Thread.currentThread() == owner_); + if (!allow) + throw new Error("Illegal Lock usage"); + if (--holds_ == 0) { + owner_ = null; + activeXid = null; + notify(); + } + } + }; + /** * System session */ Index: src/main/java/org/apache/jackrabbit/core/XASessionImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/XASessionImpl.java (revision 705186) +++ src/main/java/org/apache/jackrabbit/core/XASessionImpl.java (working copy) @@ -265,7 +265,7 @@ * @return transaction context */ private TransactionContext createTransaction(Xid xid) { - TransactionContext tx = new TransactionContext(txResources, getTransactionTimeout()); + TransactionContext tx = new TransactionContext(xid, txResources, getTransactionTimeout()); txGlobal.put(xid, tx); return tx; } Index: src/main/java/org/apache/jackrabbit/core/state/PatchedDefaultISMLocking.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/state/PatchedDefaultISMLocking.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/state/PatchedDefaultISMLocking.java (revision 0) @@ -0,0 +1,110 @@ +/* + * 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 javax.transaction.xa.Xid; + +import org.apache.jackrabbit.core.ItemId; +import org.apache.jackrabbit.core.TransactionContext; + +import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock; + +/** + * PatchedDefaultISMLocking implements the default locking strategy using + * coarse grained locking on an ItemStateManager wide read-write lock. E.g. + * while a write lock is held, no read lock can be acquired. + */ +public class PatchedDefaultISMLocking implements ISMLocking { + + private final RWLock rwLock = new RWLock(); + + /** + * {@inheritDoc} + */ + public ReadLock acquireReadLock(ItemId id) throws InterruptedException { + return new ReadLockImpl(); + } + + /** + * {@inheritDoc} + */ + public WriteLock acquireWriteLock(ChangeLog changeLog) throws InterruptedException { + return new WriteLockImpl(); + } + + public final class WriteLockImpl implements WriteLock { + + public WriteLockImpl() throws InterruptedException { + Xid currentXid = (Xid) TransactionContext.getCurrentXid(); + rwLock.setActiveXid(currentXid); + rwLock.writeLock().acquire(); + } + + /** + * {@inheritDoc} + */ + public void release() { + rwLock.writeLock().release(); + } + + /** + * {@inheritDoc} + */ + public ReadLock downgrade() throws InterruptedException { + ReadLock rLock = new ReadLockImpl(); + release(); + return rLock; + } + } + + private final class ReadLockImpl implements ReadLock { + + private ReadLockImpl() throws InterruptedException { + rwLock.readLock().acquire(); + } + + /** + * {@inheritDoc} + */ + public void release() { + rwLock.readLock().release(); + } + } + + + private final class RWLock extends ReentrantWriterPreferenceReadWriteLock { + + private Xid activeXid; + + /** + * Allow reader when there is no active writer, or current thread owns + * the write lock (reentrant). + */ + protected boolean allowReader() { + boolean defaultAllowReader = activeWriter_ == null || activeWriter_ == Thread.currentThread(); + return TransactionContext.isCurrentXid(activeXid, defaultAllowReader); + } + + /** + * Helper Method to set the active Xid + * @param id + */ + synchronized void setActiveXid(Xid xid) { + activeXid = xid; + } + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\state\PatchedDefaultISMLocking.java ___________________________________________________________________ Added: svn:eol-style + native