/* * Copyright (c) 2010-2012, 2015, 2016 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; } }