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, byte[] contextLocks) {
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 (clock < (lock & UNLOCK) || (lock & LOCK) != 0) {
if ((selfLockByte & selfLockBit) != 0)
return lock;
throw FAILURE_EXCEPTION;
}
return lock;
}
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 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));
}
}