blob: 34effcf9bc408dcdc44332eb498bc3004c827715 [file] [log] [blame]
/*
* Copyright (c) 2010-2012, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ibrahim Sallam - initial API and implementation
*/
package org.eclipse.emf.cdo.server.internal.objectivity.db;
import org.eclipse.emf.cdo.server.internal.objectivity.bundle.OM;
import org.eclipse.emf.cdo.server.internal.objectivity.clustering.ObjyPlacementManager;
import org.eclipse.emf.cdo.server.internal.objectivity.clustering.ObjyPlacementManagerImpl;
import org.eclipse.emf.cdo.server.objectivity.IObjectivityStoreConfig;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import com.objy.db.DatabaseNotFoundException;
import com.objy.db.DatabaseOpenException;
import com.objy.db.ObjyRuntimeException;
import com.objy.db.app.Connection;
import com.objy.db.app.Session;
import com.objy.db.app.oo;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class ObjyConnection
{
public static final ObjyConnection INSTANCE = new ObjyConnection();
protected Connection connection = null;
protected boolean isConnected = false;
protected String fdName = "";
// protected ObjectivityStore store = null;
private static final ContextTracer TRACER_DEBUG = new ContextTracer(OM.DEBUG, ObjyConnection.class);
// private static final ContextTracer TRACER_INFO = new ContextTracer(OM.INFO, ObjyConnection.class);
// TODO - session pools could be a configuration candidate.
private static final String SESSION_POOL_NAME_READ = "ReadSP";
private static final String SESSION_POOL_NAME_WRITE = "WriteSP";
// private static final String PoolInfo = "PoolInfo";
protected ConcurrentHashMap<String, ObjySession> readPool;
protected ConcurrentHashMap<String, ObjySession> writePool;
private ObjyPlacementManager defaultPlacementManager = null;
private Object syncObject = new Object();
private ReentrantLock lock = new ReentrantLock();
private int sessionMinCacheSize = 600;
private int sessionMaxCacheSize = 1000;
private final int minInactiveSessions = 5;
private int sessionCount = 0;
private String logDirPath = null;
private int logOption = oo.LogNone;
public ObjyConnection()
{
readPool = new ConcurrentHashMap<String, ObjySession>(5);
writePool = new ConcurrentHashMap<String, ObjySession>(5);
}
/***
* Connect to a store and an FD. TODO - We might need to allow switching of FD in the future.
*/
synchronized public void connect(IObjectivityStoreConfig storeConfig)
{
/****
* If
*/
fdName = storeConfig.getFdName();
logDirPath = storeConfig.getLogPath();
logOption = storeConfig.getLogOption();
connect();
// this.store = store;
}
synchronized public void connect(String fdName, int logOption)
{
/****
* If
*/
this.fdName = fdName;
this.logOption = logOption;
connect();
// this.store = store;
}
private void connect()
{
if (TRACER_DEBUG.isEnabled())
{
TRACER_DEBUG.trace(" SessionMinCacheSize: " + sessionMinCacheSize);
TRACER_DEBUG.trace(" SessionMaxCacheSize: " + sessionMaxCacheSize);
}
if (!isConnected)
{
try
{
if (Connection.current() == null)
{
if (logOption != oo.LogNone)
{
Connection.setLoggingOptions(logOption, true, // boolean logToFiles
true, // boolean appendLogFiles,
logDirPath, // String logDirPath,
"MainLog.txt"// String mainLogFileName
);
}
if (TRACER_DEBUG.isEnabled())
{
TRACER_DEBUG.trace(" creating new Connection");
}
connection = Connection.open(fdName, oo.openReadWrite);
connection.useContextClassLoader(true);
}
else
{
connection.addToMainLog("ObjyConnection.connect()", "...reopen connection to the FD.");
connection.setOpenMode(oo.openReadWrite);
connection.reopen();
connection.loadSchemaClasses(true);
}
isConnected = true;
}
catch (DatabaseOpenException e)
{
e.printStackTrace();
}
catch (DatabaseNotFoundException e)
{
e.printStackTrace();
}
}
}
public String getSessionPoolNameRead()
{
return SESSION_POOL_NAME_READ;
}
public String getSessionPoolNameWrite()
{
return SESSION_POOL_NAME_WRITE;
}
public ObjySession getWriteSessionFromPool(String sessionName)
{
return getSessionFromPool(sessionName);
}
public ObjySession getReadSessionFromPool(String sessionName)
{
return getSessionFromPool(sessionName);
}
protected ObjySession getSessionFromPool(String sessionName)
{
synchronized (syncObject)
{
// return connection.getSessionFromPool(getSessionPoolNameWrite(), sessionName);
ObjySession session = readPool.get(sessionName);
if (session == null)
{
if (sessionCount >= minInactiveSessions)
{
// look for an inactive one, rename it and use it.
for (ObjySession objySession : readPool.values())
{
if (objySession.isAvailable())
{
objySession.setName(sessionName);
session = objySession;
break;
}
}
}
// we are forced to create one.
if (session == null)
{
session = new ObjySession(sessionName, readPool, this);
++sessionCount;
// System.out.println(">>> IS: creating new session: " + sessionName + " - total: " + sessionCount);
readPool.put(sessionName, session);
}
}
session.join();
session.setAvailable(false);
return session;
}
}
public void disconnect()
{
if (!isConnected)
{
return;
}
// synchronized(syncObject)
{
// it's important to do the lock() call, otherwise during the test-suite
// run we can exit the test before cleaning up, and session might be
// partly terminated.
// We could change the code in cleanupSessionPool() to remove the session
// from the pool before terminating it, but this could leave some sessions
// in the connection (another issue here is the connection.reconnect()
// doesn't work all the time).
lock.lock();
if (TRACER_DEBUG.isEnabled())
{
TRACER_DEBUG.trace("ObjyConnection.disconnect() -- Start. " + toString());
}
// terminate the session and cleanup the Pool.
// TRACER_DEBUG.trace("ObjyConnection.disconnect() -- cleanup readPool. ");
cleanupSessionPool(readPool);
// TRACER_DEBUG.trace("ObjyConnection.disconnect() -- cleanup writePool. ");
cleanupSessionPool(writePool);
sessionCount = 0;
// TRACER_DEBUG.trace("ObjyConnection.disconnect() -- cleanup any other sessions. ");
// for testing we need to find out if there are any open sessions.
@SuppressWarnings("unchecked")
Vector<Session> sessions = connection.sessions();
for (Session aSession : sessions)
{
if (TRACER_DEBUG.isEnabled())
{
TRACER_DEBUG.trace("Session: " + aSession + " - open state: " + aSession.isOpen());
}
// we need to make sure that any open session is aborted, otherwise we
// can't reopen the fd.
if (aSession.isOpen())
{
try
{
aSession.join();
aSession.abort();
// IS: sometime we get exception about no transaction, although we checked
// aSession.isOpen() above.
}
catch (ObjyRuntimeException ex)
{
ex.printStackTrace();
}
finally
{
aSession.terminate();
}
}
}
// 100211:IS - Avoid closing the connection, we're seeing
// sort of schema issues doing so with 9.4.1...
/****
* try { Session session = new Session(); session.begin(); //connection.dropAllUserClasses(true);
* connection.dropAllUnregisterableClasses(); session.commit(); connection.close(); isConnected = false; } catch
* (DatabaseClosedException e) { // TODO Auto-generated catch block e.printStackTrace(); }
****/
if (TRACER_DEBUG.isEnabled())
{
TRACER_DEBUG.trace("ObjyConnection.disconnect() -- END. ");
}
lock.unlock();
}
}
// public void resetFD()
// {
// //fdManager.resetFD();
// if (Connection.current() != null)
// {
// if (!isConnected)
// connect();
//
// // for testing we need to find out if there are any open sessions.
// Vector<Session> sessions = Connection.current().sessions();
// System.out.println("Sessions still available: " + sessions.size());
// for (Session aSession : sessions)
// {
// System.out.println("Session: " + aSession + " - open state: " + aSession.isOpen());
// // we need to make sure that any open session is aborted, otherwise we
// // can't reopen the fd.
// if (aSession.isOpen())
// {
// try {
// aSession.join();
// aSession.abort();
// // IS: sometime we get exception about no transaction, although we checked
// // aSession.isOpen() above.
// } catch (ObjyRuntimeException ex) {
// ex.printStackTrace();
// } finally {
// aSession.terminate();
// }
// }
// }
//
// // Session session = new Session();
// // session.begin();
// // Iterator itr = session.getFD().containedDBs();
// // ooDBObj dbObj = null;
// // List<ooDBObj> dbList = new ArrayList<ooDBObj>();
// // while (itr.hasNext())
// // {
// // dbObj = (ooDBObj) itr.next();
// // dbList.add(dbObj);
// // }
// // itr.close();
// // session.commit();
//
// // session.begin();
// // for (ooDBObj db : dbList)
// // {
// // System.out.println("restFD() - deleting DB(" + db.getOid().getStoreString()+"):" + db.getName());
// // db.delete();
// // }
// // session.commit();
//
// // we need to wipe the schema, some tests have similar class and package
// // names which could cause tests to fail.
// // for now we'll just wipe the wole FD.
// //fdManager.resetFD_OLD();
//
// //
// // System.out.println("resetFD() - dumping catalog BEGIN.........");
// // session.begin();
// // session.getFD().dumpCatalog();
// // session.commit();
// // System.out.println("resetFD() - dumping catalog END...........");
// // session.terminate();
//
// disconnect();
// }
// }
public void registerClass(String name)
{
connection.registerClass(name);
}
public ObjyPlacementManager getDefaultPlacementManager()
{
if (defaultPlacementManager == null)
{
defaultPlacementManager = new ObjyPlacementManagerImpl();
}
return defaultPlacementManager;
}
protected void cleanupSessionPool(ConcurrentHashMap<String, ObjySession> pool)
{
for (ObjySession objySession : pool.values())
{
try
{
if (objySession.isOpen())
{
objySession.join();
objySession.abort();
// IS: sometime we get exception about no transaction, although we checked
// aSession.isOpen() above.
}
}
catch (ObjyRuntimeException ex)
{
ex.printStackTrace();
}
finally
{
// TRACER_DEBUG.trace("ObjyConnection.cleanupSessionPool() -- start terminating session. " +
// objySession.toString());
try
{
objySession.terminate();
// TRACER_DEBUG.trace("ObjyConnection.cleanupSessionPool() -- end terminating session. " +
// objySession.toString());
}
catch (ObjyRuntimeException ex)
{
ex.printStackTrace();
}
}
}
pool.clear();
}
public void setSessionMinCacheSize(int sessionMinCacheSize)
{
if (sessionMinCacheSize > this.sessionMinCacheSize)
{
this.sessionMinCacheSize = sessionMinCacheSize;
}
}
public void setSessionMaxCacheSize(int sessionMaxCacheSize)
{
if (sessionMaxCacheSize > this.sessionMaxCacheSize)
{
this.sessionMaxCacheSize = sessionMaxCacheSize;
}
}
public int getMinSessionCacheSize()
{
return sessionMinCacheSize;
}
public int getMaxSessionCacheSize()
{
return sessionMaxCacheSize;
}
}