package com.neocoretechs.bigsack.session;
import java.io.IOException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import com.neocoretechs.bigsack.btree.BTreeMain;
import com.neocoretechs.bigsack.io.pooled.ObjectDBIO;
/*
* Copyright (c) 2003, NeoCoreTechs
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* Neither the name of NeoCoreTechs nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* SessionManager class is a singleton
* that accepts connections and returns a BigSackSession object. A table of one to one sessions and
* tables is maintained. A path to the log dirs and a path to the tablespace dirs can be specified or
* a default file structure based on mode can be used if the remoteDbName is null.
* @author Groff
*/
public final class SessionManager {
private static boolean DEBUG = false;
private static Hashtable<String, BigSackSession> SessionTable = new Hashtable<String, BigSackSession>();
@SuppressWarnings("rawtypes")
private static Hashtable<?, ?> AdminSessionTable = new Hashtable();
private static Vector<String> OfflineDBs = new Vector<String>();
private static long globalTransId = System.currentTimeMillis();
//
// Sets the maximum number users
@SuppressWarnings("unused")
private static final int MAX_USERS = -1;
//
// Singleton setups:
// 1.) privatized constructor; no other class can call
private SessionManager() {
}
// 2.) create only instance, save it to private static
private static SessionManager instance = new SessionManager();
// 3.) make the instance available
public static SessionManager getInstance() {
return instance;
}
// Global transaction timestamps
private static long lastStartTime = 0L;
private static long lastCommitTime = 0L;
/*
public static String getDbPath(String dbName) {
BigSackSession dbs = SessionTable.get(dbName);
if( dbs != null )
return dbs.getDBPath();
return null;
}
public static String getRemoteDBName(String dbName) {
BigSackSession dbs = SessionTable.get(dbName);
if( dbs != null ) {
if( DEBUG )
System.out.println("SessionManager.getRemoteDBName "+dbs.getRemoteDBName()+" from "+dbName);
return dbs.getRemoteDBName();
} else
if( DEBUG )
System.out.println("SessionManager.getRemoteDBName remote name is NULL from"+dbName);
return null;
}
*/
/**
* Increment the base global trans id and return, one for each session
* @return
*/
public static long getGlobalTransId() {
return ++globalTransId;
}
/**
* Get begin transaction timestamp
*/
protected static void getBeginStamp() {
long bts = System.currentTimeMillis();
// if < or =, it started at same time (< cause we might have bumped it already)
if (bts <= lastStartTime)
++lastStartTime;
else
lastStartTime = bts;
//
}
/**
* @return Current, or end, transaction timestamp
*/
protected static long getEndStamp() {
long ets = System.currentTimeMillis();
// if < or =, it started at same time (< cause we might have bumped it already)
if (ets <= lastCommitTime)
++lastCommitTime;
else
lastCommitTime = ets;
//
return lastCommitTime;
}
/**
* Connect and return Session instance that is the session. It is possible to specify 2 separate dirs for
* storing logs and tablespace info. If remote db path is null, the structure expected is dependent on cluster
* or standalone.
* @param dbname The database name as full path
* @param remoteDBName remote database path and name, or null to use dbname path
* @param create Create database if not existing
* @return BigSackSession The session we use to control access
* @exception IOException If low level IO problem
* @exception IllegalAccessException If access to database is denied
*/
public static synchronized BigSackSession Connect(String dbname, String remoteDBName, boolean create) throws IOException, IllegalAccessException {
if( DEBUG ) {
System.out.println("Connecting to "+dbname+" using remote DB:"+remoteDBName+" create:"+create);
}
// translate user name to uid and group
// we can restrict access at database level here possibly
int uid = 0;
int gid = 1;
//if( SessionTable.size() >= MAX_USERS && MAX_USERS != -1) throw new IllegalAccessException("Maximum number of users exceeded");
if (OfflineDBs.contains(dbname))
throw new IllegalAccessException("Database is offline, try later");
BigSackSession hps = (SessionTable.get(dbname));
if (hps == null) {
// did'nt find it, create anew, throws IllegalAccessException if no go
// Global IO and main Btree index
ObjectDBIO objIO = new ObjectDBIO(dbname, remoteDBName, create, getGlobalTransId());
BTreeMain bTree = new BTreeMain(objIO);
hps = new BigSackSession(bTree, uid, gid);
SessionTable.put(dbname, hps);
if( DEBUG )
System.out.println("New session for "+dbname+" "+hps+" "+bTree+" "+objIO);
} else {
// if closed, then open, else if open this does nothing
hps.Open();
if( DEBUG )
System.out.println("Existing session for "+dbname+" "+hps);
}
//
return hps;
}
/**
* Start the DB with no logging for debugging purposes
* or to run read only without logging for some reason
* @param dbname the path to the database (path+dbname)
* @param remoteDBName The remote path to database tablespace directories (tablespace prepended to endof path) or null
* @return
* @throws IOException
* @throws IllegalAccessException
*/
public static synchronized BigSackSession ConnectNoRecovery(String dbname, String remoteDBName) throws IOException, IllegalAccessException {
if( DEBUG ) {
System.out.println("Connecting WITHOUT RECOVERY to "+dbname);
}
// translate user name to uid and group
// we can restrict access at database level here possibly
int uid = 0;
int gid = 1;
//if( SessionTable.size() >= MAX_USERS && MAX_USERS != -1) throw new IllegalAccessException("Maximum number of users exceeded");
if (OfflineDBs.contains(dbname))
throw new IllegalAccessException("Database is offline, try later");
BigSackSession hps = (SessionTable.get(dbname));
if (hps == null) {
// did'nt find it, create anew, throws IllegalAccessException if no go
// Global IO and main Btree index
if( DEBUG )
System.out.println("SessionManager.ConectNoRecovery bringing up IO");
ObjectDBIO objIO = new ObjectDBIO(dbname, remoteDBName);
if( DEBUG )
System.out.println("SessionManager.ConectNoRecovery bringing up BTree");
BTreeMain bTree = new BTreeMain(objIO);
hps = new BigSackSession(bTree, uid, gid);
if( DEBUG )
System.out.println("SessionManager.ConectNoRecovery logging session");
SessionTable.put(dbname, hps);
} else
// if closed, then open, else if open this does nothing
hps.Open();
//
return hps;
}
/**
* Set the database offline, kill all sessions using it
* @param dbname The database to offline
* @exception IOException if we can't force the close
*/
protected static synchronized void setDBOffline(String dbname)
throws IOException {
OfflineDBs.addElement(dbname);
// look for session instance, then signal close
BigSackSession hps = (SessionTable.get(dbname));
if (hps != null) {
hps.forceClose();
}
}
protected static synchronized void setDBOnline(String name) {
OfflineDBs.removeElement(name);
}
public static boolean isDBOffline(String dbname) {
return OfflineDBs.contains(dbname);
}
protected static synchronized void releaseSession(BigSackSession DS) {
SessionTable.remove(DS);
}
public static Hashtable<String, BigSackSession> getSessionTable() {
return SessionTable;
}
public static boolean contains(long transId) {
Collection<BigSackSession> sess = SessionTable.values();
Iterator<BigSackSession> its = sess.iterator();
while(its.hasNext()) {
BigSackSession sits = its.next();
if( sits.getTransactionId() == transId )
return true;
}
return false;
}
/**
* For those that wish to maintain admin tables
* @return The Hashtable of Admin sessions - you define
*/
protected static Hashtable<?, ?> getAdminSessionTable() {
return AdminSessionTable;
}
}