package org.deuce.transaction.strongiso; import java.util.concurrent.atomic.AtomicIntegerArray; import org.deuce.transaction.TransactionException; import org.deuce.transform.Exclude; @Exclude public class LockTable { // Failure transaction final private static TransactionException FAILURE_EXCEPTION = new TransactionException( "Faild on lock."); final public static int LOCKS_SIZE = 1<<20; // amount of locks - TODO add system property final public static int MASK = 0xFFFFF; final private static int LOCK = 1 << 31; final private static int UNLOCK = ~LOCK; final static private int MODULE_8 = 7; //Used for %8 final static private int DIVIDE_8 = 3; //Used for /8 final private static AtomicIntegerArray locks = new AtomicIntegerArray(LOCKS_SIZE); // array of 2^20 entries of 32-bit lock words /** * * @return <code>true</code> if lock otherwise false. * @throws TransactionException incase the lock is hold by other thread. */ public static boolean lock( int lockIndex, byte[] contextLocks) throws TransactionException{ final int lock = locks.get(lockIndex); final int selfLockIndex = lockIndex>>>DIVIDE_8; final byte selfLockByte = contextLocks[selfLockIndex]; final byte selfLockBit = (byte)(1 << (lockIndex & MODULE_8)); if( (lock & LOCK) != 0){ //is already locked? if( (selfLockByte & selfLockBit) != 0) // check for self locking return false; throw FAILURE_EXCEPTION; } boolean isLocked = locks.compareAndSet(lockIndex, lock, lock | LOCK); if( !isLocked) throw FAILURE_EXCEPTION; contextLocks[selfLockIndex] |= selfLockBit; //mark in self locks return true; } public static int checkLock(int lockIndex, int clock) { int lock = locks.get(lockIndex); if( clock < (lock & UNLOCK)) // check the clock without lock, TODO check if this is the best way throw FAILURE_EXCEPTION; return lock; } public static void checkLock(int lockIndex, int clock, int expected) { int lock = locks.get(lockIndex); if( lock != expected || clock < (lock & UNLOCK) || (lock & LOCK) != 0) throw FAILURE_EXCEPTION; } public static void unLock( int lockIndex, byte[] contextLocks){ int lockedValue = locks.get( lockIndex); int unlockedValue = lockedValue & UNLOCK; locks.set(lockIndex, unlockedValue); clearSelfLock(lockIndex, contextLocks); } public static void setAndReleaseLock( int hash, int newClock, byte[] contextLocks){ int lockIndex = hash & MASK; locks.set(lockIndex, newClock); clearSelfLock( lockIndex, contextLocks); } /** * Clears lock marker from self locking array */ private static void clearSelfLock( int lockIndex, byte[] contextLocks){ // clear marker TODO might clear all bits contextLocks[lockIndex>>>DIVIDE_8] &= ~(1 << (lockIndex & MODULE_8)); } }