package com.g414.haildb.tpl;
import java.util.Map;
import com.g414.haildb.Cursor;
import com.g414.haildb.Cursor.LockMode;
import com.g414.haildb.Cursor.SearchMode;
import com.g414.haildb.Database;
import com.g414.haildb.IndexDef;
import com.g414.haildb.TableDef;
import com.g414.haildb.Transaction;
import com.g414.haildb.Transaction.TransactionLevel;
import com.g414.haildb.Transaction.TransactionState;
import com.g414.haildb.Tuple;
public class DatabaseTemplate {
public interface TransactionCallback<T> {
public T inTransaction(Transaction txn);
}
protected final Database database;
public DatabaseTemplate(Database database) {
this.database = database;
}
public <T> T inTransaction(TransactionLevel level,
TransactionCallback<T> callback) throws Exception {
Transaction txn = null;
try {
txn = database.beginTransaction(level);
return callback.inTransaction(txn);
} catch (Exception e) {
if (txn != null) {
if (txn.getState().equals(TransactionState.NOT_STARTED)) {
txn.release();
} else {
txn.rollback();
}
txn = null;
}
throw e;
} finally {
if (txn != null) {
if (txn.getState().equals(TransactionState.NOT_STARTED)) {
txn.release();
} else {
txn.commit();
}
}
}
}
public Map<String, Object> load(Transaction txn, TableDef def,
Map<String, Object> data) {
IndexDef primary = def.getPrimaryIndex();
Cursor c = null;
Tuple toFind = null;
Tuple toReturn = null;
try {
c = txn.openTable(def);
toFind = c.createClusteredIndexSearchTuple(data);
c.find(toFind, SearchMode.GE);
if (c.isPositioned() && c.hasNext()) {
toReturn = c.createClusteredIndexReadTuple();
c.readRow(toReturn);
Map<String, Object> found = toReturn.valueMap();
if (!KeyHelper.matchesPrimaryKey(primary, data, found)) {
return null;
}
} else {
return null;
}
Map<String, Object> res = toReturn.valueMap();
toReturn.clear();
return res;
} finally {
if (toReturn != null) {
toReturn.delete();
}
if (toFind != null) {
toFind.delete();
}
if (c != null) {
c.close();
}
}
}
public void insert(Transaction txn, TableDef def, Map<String, Object> data) {
Cursor c = null;
Tuple toInsert = null;
try {
c = txn.openTable(def);
c.setLockMode(LockMode.INTENTION_EXCLUSIVE);
c.lock(LockMode.LOCK_EXCLUSIVE);
toInsert = c.createClusteredIndexReadTuple();
c.insertRow(toInsert, data);
toInsert.clear();
} finally {
if (toInsert != null) {
toInsert.delete();
}
if (c != null) {
c.close();
}
}
}
public boolean update(Transaction txn, TableDef def,
Map<String, Object> data) {
IndexDef primary = def.getPrimaryIndex();
Cursor c = null;
Tuple toFind = null;
Tuple toUpdate = null;
try {
c = txn.openTable(def);
c.setLockMode(LockMode.INTENTION_EXCLUSIVE);
c.lock(LockMode.LOCK_EXCLUSIVE);
toFind = c.createClusteredIndexSearchTuple(data);
c.find(toFind, SearchMode.GE);
if (c.isPositioned() && c.hasNext()) {
toUpdate = c.createClusteredIndexReadTuple();
c.readRow(toUpdate);
Map<String, Object> found = toUpdate.valueMap();
if (!KeyHelper.matchesPrimaryKey(primary, data, found)) {
return false;
}
} else {
return false;
}
c.updateRow(toUpdate, data);
toUpdate.clear();
return true;
} finally {
if (toUpdate != null) {
toUpdate.delete();
}
if (toFind != null) {
toFind.delete();
}
if (c != null) {
c.close();
}
}
}
public boolean insertOrUpdate(Transaction txn, TableDef def,
Map<String, Object> data) {
IndexDef primary = def.getPrimaryIndex();
Cursor c = null;
Tuple toFind = null;
Tuple toInsert = null;
Tuple toUpdate = null;
try {
c = txn.openTable(def);
c.setLockMode(LockMode.INTENTION_EXCLUSIVE);
c.lock(LockMode.LOCK_EXCLUSIVE);
toFind = c.createClusteredIndexSearchTuple(data);
c.find(toFind, SearchMode.GE);
if (c.isPositioned() && c.hasNext()) {
toUpdate = c.createClusteredIndexReadTuple();
c.readRow(toUpdate);
Map<String, Object> found = toUpdate.valueMap();
if (KeyHelper.matchesPrimaryKey(primary, data, found)) {
c.updateRow(toUpdate, data);
toUpdate.clear();
return true;
}
}
toInsert = c.createClusteredIndexReadTuple();
c.insertRow(toInsert, data);
toInsert.clear();
return false;
} finally {
if (toInsert != null) {
toInsert.delete();
}
if (toUpdate != null) {
toUpdate.delete();
}
if (toFind != null) {
toFind.delete();
}
if (c != null) {
c.close();
}
}
}
public boolean delete(Transaction txn, TableDef def,
Map<String, Object> data) {
IndexDef primary = def.getPrimaryIndex();
Cursor c = null;
Tuple toFind = null;
Tuple toDelete = null;
try {
c = txn.openTable(def);
c.setLockMode(LockMode.INTENTION_EXCLUSIVE);
c.lock(LockMode.LOCK_EXCLUSIVE);
toFind = c.createClusteredIndexSearchTuple(data);
c.find(toFind, SearchMode.GE);
if (c.isPositioned() && c.hasNext()) {
toDelete = c.createClusteredIndexReadTuple();
c.readRow(toDelete);
Map<String, Object> found = toDelete.valueMap();
if (KeyHelper.matchesPrimaryKey(primary, data, found)) {
c.deleteRow();
toDelete.clear();
return true;
}
}
return false;
} finally {
if (toDelete != null) {
toDelete.delete();
}
if (toFind != null) {
toFind.delete();
}
if (c != null) {
c.close();
}
}
}
}