/****************************************************************************** * * Copyright: Intellectual Property of Four Elements Capital Pte Ltd, Singapore. * All rights reserved. * ******************************************************************************/ package com.fourelementscapital.db; import java.sql.Connection; import java.sql.DriverManager; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.jcs.JCS; import org.apache.commons.jcs.access.CacheAccess; import org.apache.commons.jcs.engine.behavior.IElementAttributes; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.fourelementscapital.db.mariadb.BBSyncDBMariaDB; import com.fourelementscapital.db.mariadb.ConstructQueryDBMariaDB; import com.fourelementscapital.db.mariadb.ContractDBMariaDB; import com.fourelementscapital.db.mariadb.DBManagerDBMariaDB; import com.fourelementscapital.db.mariadb.FlexiFieldDBMariaDB; import com.fourelementscapital.db.mariadb.IExecDBMariaDB; import com.fourelementscapital.db.mariadb.InfrastructureDBMariaDB; import com.fourelementscapital.db.mariadb.RFunctionDBMariaDB; import com.fourelementscapital.db.mariadb.ReferenceDBMariaDB; import com.fourelementscapital.db.mariadb.SchedulerDBMariaDB; import com.fourelementscapital.db.mariadb.UtilDBMariaDB; import com.jolbox.bonecp.BoneCP; import com.jolbox.bonecp.BoneCPConfig; import com.jolbox.bonecp.Statistics; /** * Super class of all db classes */ public class SuperDB { // get db name from config file : public static final String DB_NAME_BBSYNC = "bbsync"; //public static final String DB_NAME_R_FUNCTION = "rfunction"; public static final String DB_NAME_R_FUNCTION = "quantlib"; public static final String DB_NAME_TRADING = "trading"; public static final String DB_NAME_TRADINGREF = "tradingRef"; public static final String DB_NAME_IEXEC = "iexec"; public static final String DB_NAME_INFRASTRUCTURE = "infrastructure"; public static boolean CONNECTION_POOL_ACTIVE=false; public static boolean CONNECTION_POOL_CONN_COUNT=true; private static int db_close_timeout = 5; // default : 5 minutes private Connection con = null; private String db=null; private String driver = "com.mysql.jdbc.Driver"; private static ConcurrentHashMap connPools=new ConcurrentHashMap(); private static Vector connections=new Vector(); private Date connectedDate=null; private String callStack=null; public static String MY_SQL_DRIVER="com.mysql.jdbc.Driver"; private String tablename=null; private Logger log=LogManager.getLogger(SuperDB.class.getName()); //private Logger log = LogManager.getLogger(ExecuteRMgmt.class.getName()); private static long count=0; private static long delays=0; //private static JCS cache=null; private static CacheAccess cache=null; /** * Get DB close timeout * @return timeout */ public static int getDbCloseTimeout() { if(Config.getString("db_close_timeout") != null) { db_close_timeout = Integer.parseInt(Config.getString("db_close_timeout")); } return db_close_timeout; } /** * Get connected date * @return connected date */ public Date getConnectedDate() { return connectedDate; } /** * Set connected date * @param connectedDate connected date */ public void setConnectedDate(Date connectedDate) { this.connectedDate = connectedDate; } /** * Get call stack * @return call stack */ public String getCallStack() { return callStack; } /** * Set call stack * @param callStack call stack */ public void setCallStack(String callStack) { this.callStack = callStack; } /** * Connect to specific database * @param db database * @throws Exception */ public void connectDB(String db) throws Exception { // Establish the connection. this.db=db; Date start=new Date(); String marketConnectionURL = Utils.getConfig4E(".CONFIG4E_JDBC_CONNECTIONSTRING_" + db.toUpperCase()); // throw exception // add parameter to prevent timestamp converting error marketConnectionURL += "&useUnicode=true&useFastDateParsing=false&characterEncoding=UTF-8"; // replace driver if marketConnectionURL contains 'sqlserver'. i.e. 'jdbc:sqlserver://10.153.64.3:1433;databaseName=infrastructure;integratedSecurity=false;user=dbuser;password=dbuser' if (marketConnectionURL.contains("sqlserver")) { this.driver="com.microsoft.sqlserver.jdbc.SQLServerDriver"; } if(CONNECTION_POOL_ACTIVE){ if(connPools.get(db)==null){ setupConnectionPool(marketConnectionURL); } if(this.con!=null && !this.con.isClosed()) { //don't assing new printOrphanConns(); }else{ this.con=connPools.get(db).getAsyncConnection().get(); this.setCallStack(collectErrorStack(new Exception().getStackTrace())); this.setConnectedDate(new Date()); //connPools.get(db).getAsyncConnection() connections.add(this); } }else{ Class.forName(this.driver); log.debug("marketConnectionURL:"+marketConnectionURL); if(this.con!=null && !this.con.isClosed()) { //don't assing new //System.out.println("~~~SuperDB.connectDB(): Reuse connection, Already connection is active"); printOrphanConns(); }else{ this.con = DriverManager.getConnection(marketConnectionURL); connections.add(this); this.setCallStack(collectErrorStack(new Exception().getStackTrace())); this.setConnectedDate(new Date()); //DatabaseMetaData md=this.con.getMetaData(); //md.get } } //log.debug("conn opened in "+diff+" ms" +" counter:"+count); if(CONNECTION_POOL_CONN_COUNT) { Date end=new Date(); long diff=end.getTime()-start.getTime(); delays+=diff; count++; } } /** * Get cache * @return cache * @throws Exception */ private static CacheAccess getCache() throws Exception { if(cache==null) cache=JCS.getInstance("SuperDB-cache"); return cache; } /** * Print orphan connections * @throws Exception */ private void printOrphanConns() throws Exception { if(getCache().get("delayPrint")!=null){ System.out.println("~~~SuperDB.connectDB(): Reuse connection, Already connection is active"); }else{ IElementAttributes att= getCache().getDefaultElementAttributes(); att.setMaxLife(600); getCache().put("delayPrint","delay",att); try{ System.out.println("=====SuperDB.connectDB(): Reuse connection, Already connection is active====\n"+collectErrorStack(new Exception().getStackTrace())); //Thread.dumpStack(); }catch(Exception e){ //e.printStackTrace(); } } } /** * Setup connection pool * @param marketConnectionURL market connection URL * @throws Exception */ private synchronized void setupConnectionPool(String marketConnectionURL) throws Exception { Class.forName(this.driver); // load the DB driver BoneCPConfig config = new BoneCPConfig(); // create a new configuration object config.setJdbcUrl(marketConnectionURL); // set the JDBC url config.setMinConnectionsPerPartition(1); config.setMaxConnectionsPerPartition(25); config.setPartitionCount(2); //set connectinos returned to pool lives very short //config.setAcquireIncrement(1); config.setMaxConnectionAgeInSeconds(10); config.setLogStatementsEnabled(true); connPools.put(db, new BoneCP(config)); } /** * Close all connections */ public static void closeAllConnections(){ for(Iterator it=connPools.keySet().iterator();it.hasNext();) { String key=(String)it.next(); BoneCP bcp=(BoneCP)connPools.get(key); bcp.shutdown(); connPools.remove(key); } } /** * Get connection count * @return connection count */ public static String getConnectionCount() { String t="Total Conn:"+count+" total delay:"+delays+" average:"+(delays/count)+" ms"; return t; } /** * Get connection objects * @return connection objects */ public static List getConnectionObjs() { return connections; } /** * Reset connection count */ public static void connectionCountReset() { count=0; delays=0; } /** * Get connection status * @return connection status */ public static String getConnStatus(){ String t="\n"; for(Iterator it=connPools.keySet().iterator();it.hasNext();) { String key=(String)it.next(); BoneCP bcp=(BoneCP)connPools.get(key); Statistics st=bcp.getStatistics(); t+="Db:"+key+" --->"; t+=" Total Conn:"+st.getTotalCreatedConnections()+" Free:"+st.getTotalFree()+" Cached hits:"+st.getCacheHits()+" Cached miss:"+st.getCacheMiss()+" Req Conn:"+st.getConnectionsRequested()+" Leased:"+st.getTotalLeased(); t+="\n"; //bcp.shutdown(); //connPools.remove(key); } return t; } /** * Get opened connections * @return connection count */ public static String getOpenedConnections() { return "Size:"+connections.size(); } /** * Collect error stack * @return error stack * @throws Exception */ public static String collectStack() throws Exception { return collectErrorStack(new Exception().getStackTrace()); } /** * Kill connections * @param minsbefore minutes before * @throws Exception */ public static void killConnections(int minsbefore) throws Exception { Logger log=LogManager.getLogger(SuperDB.class.getName()); Vector v=new Vector(); synchronized(connections) { //System.out.println("------" ); for(SuperDB sdb: connections) { Calendar opened=Calendar.getInstance(); opened.setTime(sdb.getConnectedDate()); Calendar now=Calendar.getInstance(); now.setTime(new Date()); now.add(Calendar.MINUTE, -minsbefore); long diff=new Date().getTime()-sdb.getConnectedDate().getTime(); diff=diff/1000; SimpleDateFormat sdf=new SimpleDateFormat("dd-MMM HH:mm:ss"); //System.out.println("Opened at:"+sdf.format(sdb.getConnectedDate())+" now:"+sdf.format(new Date())+"con id: is expired:"+now.after(opened)+" diff:"+diff+" seconds" ); if(now.after(opened)){ //System.out.println("closing connection: as it is expired"); //sdb.closeDB(); v.add(sdb); } } } if(v.size()>0){ log.error("~~~~~~Closing "+v.size()+" connections after "+minsbefore+" minutes"); } for(SuperDB sdb: v) { sdb.closeDB(); } } /** * Collect error stack * @return error stack * @throws Exception */ private static String collectErrorStack(StackTraceElement[] sts) throws Exception { String rtn=""; SimpleDateFormat sdf=new SimpleDateFormat("dd-MMM HH:mm:ss.SSS "); rtn+="\n-- "+sdf.format(new Date())+" Thread:"+Thread.currentThread().getId()+" - "+Thread.currentThread().getName()+" --\n"; for(int loop=0;loop