package org.deuce.transaction.tl2;

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)|| (lock & LOCK) != 0)
			throw FAILURE_EXCEPTION;
				
		return lock;
	}
	
	public static int checkLock(int lockIndex, int clock, byte[] contextLocks) {
		int lock = locks.get(lockIndex);

		if( clock < (lock & UNLOCK))
			throw FAILURE_EXCEPTION;
		
		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
				throw FAILURE_EXCEPTION; // not self locked
		}
		
		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)); 
	}
}

@@ -2068,22 +2068,68 @@
 ION;
+%09
 %0D%0A
-
 %09%09%0D%0A%09%09
-final 
+if( (lock & LOCK) != 0)%7B  //is already locked?%0D%0A%09%09%09
 int 
@@ -2161,38 +2161,33 @@
 %3E%3E%3EDIVIDE_8;%0D%0A%09%09
-final 
+%09
 byte selfLockByt
@@ -2214,38 +2214,33 @@
 fLockIndex%5D;%0D%0A%09%09
-final 
+%09
 byte selfLockBit
@@ -2284,62 +2284,8 @@
 );%0D%0A
-%09%09%0D%0A%09%09if( (lock & LOCK) != 0)%7B  //is already locked?%0D%0A
 %09%09%09i

Update src/java/org/deuce/transaction/tl2/LockTable.java