/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.lock;
import org.apache.log4j.Logger;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
/**
* The lock class
*/
public class Lock {
/**
* locker held this lock
*/
int lockerId;
/**
* object this lock applies to
*/
LockableObject object;
/**
* mode of this lock, for the constant of mode ,pls refer to LockManager
*/
int mode;
/**
* reference count on this lock
*/
int refCount;
/**
* status of this lock
*/
int status;
/**
* Free list or holder/waiter list.
*/
Lock links;
/**
* List of locks held by a locker.
*/
Lock locker_links;
/**
* the flag of notified
*/
private boolean bNotified;
private boolean keepLockAutoCommit;//keep the read lock when autocommit = false;
public String ThreadName;
/**
* Lock's status
*/
public static final int LSTAT_FREE = 0; // Lock is unallocated.
public static final int LSTAT_ABORTED = 1;//Lock belongs to an aborted txn.
public static final int LSTAT_ERR = 2; //Lock is bad
public static final int LSTAT_HELD = 3; // Lock is currently held.
public static final int LSTAT_NOGRANT = 4;// Lock is not granted.
public static final int LSTAT_PENDING = 5;//Lock is waiting and has been promoted;
//waiting for the owner to run and upgrade it to held
public static final int LSTAT_WAITING = 6;// Lock is one the wait queue
// invalid lock mode constant
public static final int LOCK_INVALID = -1;
private static final Logger logger = Logger.getLogger(Lock.class);
/**
* Constructor
*/
public Lock() {
reset();
}
/**
* set the member variable to initial state
*/
public void reset() {
lockerId = 0;
object = null;
mode = LOCK_INVALID;
refCount = 0;
status = LSTAT_FREE;
locker_links = null;
links = null;
bNotified = false;
keepLockAutoCommit = false;
ThreadName = null;
}
public void setKeepLockAutoCommit(boolean flag) {
this.keepLockAutoCommit = flag;
}
public boolean getKeepLockAutoCommit() {
return this.keepLockAutoCommit;
}
//block the thread that hold this lock
synchronized void lock() throws ChaiDBException {
try {
if (!bNotified) wait();
} catch (InterruptedException e) {
String errMessage = "The waiting lock is interrupted" + e.getMessage();
logger.error(errMessage);
throw new ChaiDBException(ErrorCode.LOCK_INTERRUPTED, errMessage);
}
}
//notify the thread that hold this lock
synchronized void unlock() {
bNotified = true;
notify();
}
public String toString() {
String mode, status;
StringBuffer sbuf = new StringBuffer();
switch (this.mode) {
case LockManager.LOCK_NG:
mode = "NG";
break;
case LockManager.LOCK_READ:
mode = "READ";
break;
case LockManager.LOCK_WRITE: // Exclusive/write.
mode = "WRITE";
break;
case LockManager.LOCK_WAIT: //Wait event
mode = "WAIT";
break;
case LockManager.LOCK_IWRITE: // Intent exclusive/write.
mode = "IWRITE";
break;
case LockManager.LOCK_IREAD: // Intent to share/read.
mode = "IREAD";
break;
case LockManager.LOCK_IWR: // Intent to read and write.
mode = "IWR";
break;
default:
mode = "UNKNOWN";
break;
}
switch (this.status) {
case LSTAT_FREE:
status = "FREE";
break;
case LSTAT_ABORTED:
status = "ABORT";
break;
case LSTAT_ERR:
status = "ERROR";
break;
case LSTAT_HELD:
status = "HELD";
break;
case LSTAT_NOGRANT:
status = "NONE";
break;
case LSTAT_WAITING:
status = "WAIT";
break;
case LSTAT_PENDING:
status = "PENDING";
break;
default:
status = "UNKNOWN";
break;
}
String lineSep = System.getProperty("line.separator");
sbuf.append("<lock>").append(lineSep)
.append("<lockerid>").append(lockerId).append("</lockerid>").append(lineSep)
.append("<mode>").append(mode).append("</mode>").append(lineSep)
.append("<status>").append(status).append("</status>").append(lineSep)
.append("<Thread>").append(this.ThreadName).append("</Thread>").append(lineSep)
.append("<refcount>").append(refCount).append("</refcount>").append(lineSep);
if ((object != null) && (object.lockObject != null)) sbuf.append(object.lockObject);
else sbuf.append("<object>null</object>").append(lineSep);
sbuf.append("</lock>").append(lineSep);
return sbuf.toString();
}
public int getRefCount() {
return this.refCount;
}
/**
* get locker Id
*/
public int getLockerId() {
return lockerId;
}
/**
* get locked object type
*/
public byte getLockObjectType() {
if ((object != null) && (object.lockObject != null)) return object.lockObject.getType();
else return -1;
}
/**
* get locked object
*/
public Object getLockObject() {
if ((object != null) && (object.lockObject != null)) return object.lockObject.getObject();
else return null;
}
/**
* add by leon for debug
*
* @return id of object locked by this lock
*/
public long getLockID() {
if ((object != null) && (object.lockObject != null)) return object.lockObject.getId();
else return -1;
}
/**
* get the lock mode
*
* @return mode of lock
*/
public int getMode() {
return mode;
}
}