/*
* 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;
import org.apache.log4j.Logger;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.exception.ErrorCode;
import org.chaidb.db.index.btree.Debug;
import org.chaidb.db.lock.Lock;
import org.chaidb.db.lock.LockTable;
import org.chaidb.db.transaction.Transaction;
import org.chaidb.db.transaction.TransactionManager;
import java.util.HashMap;
import java.util.LinkedList;
/**
* This class holds metadata for a kernel transaction
*/
public class KernelContext {
private static final Logger logger = Logger.getLogger(KernelContext.class);
/**
* transaction reference
*/
private Transaction txn;
/**
* Whether need to flash to B-Tree, only used for in-memory index
* Added by Jason Nov 30,2001
*/
private boolean bOnlyMemory;
/**
* Locker ID associated with txn. If no txn, it is the one in whole session
*/
public int locker;
/**
* The treeid --> locks map.
*/
private HashMap treeid2lock = null;
/**
* hack to avoid flush OM recursively. Otherwise,ConcurrentModificationException
*/
private boolean hasflushOM = false;
public boolean isHasflushOM() {
return hasflushOM;
}
public void setHasflushOM(boolean hasflushOM) {
this.hasflushOM = hasflushOM;
}
/**
* default construct
*/
public KernelContext() {
locker = Db.getLockManager().id();
bOnlyMemory = false;
treeid2lock = new HashMap();
}
/**
* set transaction reference
*/
public void setTxn(Transaction txn) {
this.txn = txn;
if (txn != null) txn.setKernelContext(this);
}
/**
* get transaction reference
*/
public Transaction getTxn() {
return txn;
}
/**
* Gets whether need log.
*
* @return Whether need log.
*/
public boolean getNeedLog() throws ChaiDBException {
if (txn == null) // transaction turn off
return false;
else if (txn.getTxnId() == TransactionManager.TXN_INVALID_ID)
throw new ChaiDBException(ErrorCode.DB_SERVER_SHUTDOWN);
else return true;
}
/**
* Adds special lock to the linked list associated with by special treeId.
*
* @param treeName The tree id which the lock should be associted with.
* @param lock The lock should be associated with special tree id.
*/
public void addLock(String treeName, Lock lock) throws ChaiDBException {
if (lock == null) throw new ChaiDBException(ErrorCode.LOCK_NULL, "The lock passed by parameter is null");
// if (!treeid2lock.containsKey(treeId)) {
// treeid2lock.put(treeId, lock);
// } else { //permit to add multi-locks on same lock for same identity
// Lock tmpLock = (Lock)treeid2lock.get(treeId);
// if (tmpLock != lock)
// throw new ChaiDBException(ErrorCode.ALERADY_EXIST_LOCK, "Already exit lock on this tree id");
// }
LinkedList locks = (LinkedList) treeid2lock.get(treeName);
if (locks == null) {
locks = new LinkedList();
treeid2lock.put(treeName, locks);
}
locks.addFirst(lock);
}
/**
* Gets the lock list associates with special tree id.
*
* @param treeName The tree id with which the lock list associate.
* @return The lock list with which the tree id associates.
*/
public Lock getLock(String treeName) throws ChaiDBException {
LinkedList lock;
if (treeid2lock.containsKey(treeName)) {
lock = (LinkedList) treeid2lock.get(treeName);
if (lock == null || lock.size() == 0)
throw new ChaiDBException(ErrorCode.LOCK_NULL, "The lock is null in the entry which treeid is exist.");
else {
if (lock.size() == 1) {
removeLock(treeName);
}
return (Lock) lock.removeFirst();
}
} else {
return null;
}
}
public void checkLock(String treeName) throws ChaiDBException {
if (!treeid2lock.containsKey(treeName)) {
if (Debug.checkLock_DEBUG) {
logger.error(new Throwable("please aquire lock on:" + treeName));
logger.error(LockTable.getInstance().getDump());
throw new ChaiDBException(ErrorCode.LOCK_NULL, "please aquire lock");
}
}
}
/**
* Removes the lock associates with tree id.
*
* @param treeName The tree id with which the lock removed associates
* @throws ChaiDBException
*/
public void removeLock(String treeName) throws ChaiDBException {
if (treeid2lock.containsKey(treeName)) {
treeid2lock.remove(treeName);
} else {
throw new ChaiDBException(ErrorCode.LOCK_NO_HOLD, "The lock which should be removed by treeid don't be hold.");
}
}
/**
* Get locker ID.
*
* @return if txn nonexists, return preallocated locker.Otherwise, return txn id
*/
public int getLocker() {
return txn == null ? locker : txn.getTxnId();
}
/**
* Set only memory flag
*/
public void setOnlyMemory(boolean bOnlyMemory) {
this.bOnlyMemory = bOnlyMemory;
}
/**
* Get only memory flag
*/
public boolean getOnlyMemory() {
return bOnlyMemory;
}
}