[ 1801842 ] DB connection fix & improvements for concurrent threads.

- Integrating contribution from the Posterita Team.
This commit is contained in:
Heng Sin Low 2007-09-26 09:08:59 +00:00
parent 67798db401
commit 87002bb763
8 changed files with 3681 additions and 3786 deletions

View File

@ -18,5 +18,6 @@
<classpathentry kind="lib" path="/tools/lib/postgresql.jar"/> <classpathentry kind="lib" path="/tools/lib/postgresql.jar"/>
<classpathentry kind="lib" path="/tools/lib/ocrs12.jar"/> <classpathentry kind="lib" path="/tools/lib/ocrs12.jar"/>
<classpathentry kind="lib" path="/tools/lib/ojdbc14.jar"/> <classpathentry kind="lib" path="/tools/lib/ojdbc14.jar"/>
<classpathentry kind="lib" path="/tools/lib/c3p0-0.9.1.2.jar"/>
<classpathentry kind="output" path="build"/> <classpathentry kind="output" path="build"/>
</classpath> </classpath>

View File

@ -276,6 +276,10 @@ public interface AdempiereDatabase
// public String getDataType (int displayType, int precision, // public String getDataType (int displayType, int precision,
// boolean defaultValue) // boolean defaultValue)
/**
* Default sql use to test whether a connection is still valid
*/
public final static String DEFAULT_CONN_TEST_SQL = "SELECT Version FROM AD_System";
} // AdempiereDatabase } // AdempiereDatabase

File diff suppressed because it is too large Load Diff

View File

@ -35,16 +35,25 @@ import org.compiere.dbPort.Convert;
import org.compiere.dbPort.Convert_PostgreSQL; import org.compiere.dbPort.Convert_PostgreSQL;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DisplayType; import org.compiere.util.DisplayType;
import org.compiere.util.Ini;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/** /**
* PostgreSQL Database Port * PostgreSQL Database Port
* *
* @author @author Jorg Janke, Victor P<EFBFBD>rez * @author @author Jorg Janke, Victor P<EFBFBD>rez
* @version $Id: DB_PostgreSQL.java,v 1.23 2005/03/11 20:29:01 jjanke Exp $ * @version $Id: DB_PostgreSQL.java,v 1.23 2005/03/11 20:29:01 jjanke Exp $
* ---
* Modifications: removed static references to database connection and instead always
* get a new connection from database pool manager which manages all connections
* set rw/ro properties for the connection accordingly.
* @author Ashley Ramdass (Posterita)
*/ */
public class DB_PostgreSQL implements AdempiereDatabase public class DB_PostgreSQL implements AdempiereDatabase
{ {
public Convert getConvert() {
public Convert getConvert() {
return m_convert; return m_convert;
} }
@ -58,11 +67,14 @@ public class DB_PostgreSQL implements AdempiereDatabase
/** Driver */ /** Driver */
private org.postgresql.Driver s_driver = null; private org.postgresql.Driver s_driver = null;
/** Driver class */
public static final String DRIVER = "org.postgresql.Driver";
/** Default Port */ /** Default Port */
public static final int DEFAULT_PORT = 5432; public static final int DEFAULT_PORT = 5432;
/** Data Source */ /** Data Source */
private org.postgresql.ds.PGPoolingDataSource m_ds = null; private ComboPooledDataSource m_ds = null;
/** Statement Converter */ /** Statement Converter */
private Convert_PostgreSQL m_convert = new Convert_PostgreSQL(); private Convert_PostgreSQL m_convert = new Convert_PostgreSQL();
@ -80,6 +92,8 @@ public class DB_PostgreSQL implements AdempiereDatabase
/** Logger */ /** Logger */
private static CLogger log = CLogger.getCLogger (DB_PostgreSQL.class); private static CLogger log = CLogger.getCLogger (DB_PostgreSQL.class);
private static int m_maxbusyconnections = 0;
/** /**
* Get Database Name * Get Database Name
* @return database short name * @return database short name
@ -220,9 +234,21 @@ public class DB_PostgreSQL implements AdempiereDatabase
public String toString() public String toString()
{ {
StringBuffer sb = new StringBuffer("DB_PostgreSQL["); StringBuffer sb = new StringBuffer("DB_PostgreSQL[");
sb.append(m_connection) sb.append(m_connectionURL);
.append("]"); try
return sb.toString(); {
StringBuffer logBuffer = new StringBuffer(50);
logBuffer.append("# Connections: ").append(m_ds.getNumConnections());
logBuffer.append(" , # Busy Connections: ").append(m_ds.getNumBusyConnections());
logBuffer.append(" , # Idle Connections: ").append(m_ds.getNumIdleConnections());
logBuffer.append(" , # Orphaned Connections: ").append(m_ds.getNumUnclosedOrphanedConnections());
}
catch (Exception e)
{
sb.append("=").append(e.getLocalizedMessage());
}
sb.append("]");
return sb.toString();
} // toString } // toString
/** /**
@ -231,7 +257,22 @@ public class DB_PostgreSQL implements AdempiereDatabase
*/ */
public String getStatus() public String getStatus()
{ {
return ""; if (m_ds == null)
{
return null;
}
StringBuffer sb = new StringBuffer();
try
{
sb.append("# Connections: ").append(m_ds.getNumConnections());
sb.append(" , # Busy Connections: ").append(m_ds.getNumBusyConnections());
sb.append(" , # Idle Connections: ").append(m_ds.getNumIdleConnections());
sb.append(" , # Orphaned Connections: ").append(m_ds.getNumUnclosedOrphanedConnections());
}
catch (Exception e)
{}
return sb.toString();
} // getStatus } // getStatus
/************************************************************************* /*************************************************************************
@ -482,20 +523,50 @@ public class DB_PostgreSQL implements AdempiereDatabase
if (m_ds != null) if (m_ds != null)
return m_ds; return m_ds;
//org.postgresql.ds.PGPoolingDataSource ds = new org.postgresql.ds.PGPoolingDataSource(); try
org.postgresql.jdbc3.Jdbc3PoolingDataSource ds = new org.postgresql.jdbc3.Jdbc3PoolingDataSource(); {
System.setProperty("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDataSourceName("AdempiereDS");
cpds.setDriverClass(DRIVER);
//loads the jdbc driver
cpds.setJdbcUrl(getConnectionURL(connection));
cpds.setUser(connection.getDbUid());
cpds.setPassword(connection.getDbPwd());
cpds.setPreferredTestQuery(DEFAULT_CONN_TEST_SQL);
cpds.setIdleConnectionTestPeriod(120);
cpds.setAcquireRetryAttempts(5);
//cpds.setCheckoutTimeout(60);
ds.setDataSourceName("AdempiereDS"); if (Ini.isClient())
ds.setServerName(connection.getDbHost()); {
ds.setDatabaseName(connection.getDbName()); cpds.setInitialPoolSize(1);
ds.setUser(connection.getDbUid()); cpds.setMinPoolSize(1);
ds.setPassword(connection.getDbPwd()); cpds.setMaxPoolSize(15);
ds.setPortNumber(connection.getDbPort()); cpds.setMaxIdleTimeExcessConnections(1200);
ds.setMaxConnections(50); cpds.setMaxIdleTime(600);
ds.setInitialConnections(0); m_maxbusyconnections = 12;
}
else
{
cpds.setInitialPoolSize(10);
cpds.setMinPoolSize(5);
cpds.setMaxPoolSize(150);
cpds.setMaxIdleTimeExcessConnections(1200);
cpds.setMaxIdleTime(900);
m_maxbusyconnections = 120;
}
//new InitialContext().rebind("DataSource", source); cpds.setUnreturnedConnectionTimeout(1200);
m_ds = ds; cpds.setDebugUnreturnedConnectionStackTraces(true);
m_ds = cpds;
}
catch (Exception ex)
{
m_ds = null;
log.log(Level.SEVERE, "Could not initialise C3P0 Datasource", ex);
}
return m_ds; return m_ds;
} }

View File

@ -16,9 +16,13 @@
*****************************************************************************/ *****************************************************************************/
package org.compiere.model; package org.compiere.model;
import java.rmi.RemoteException;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.*;
import org.compiere.db.CConnection;
import org.compiere.interfaces.Server;
import org.compiere.util.*; import org.compiere.util.*;
/** /**
@ -37,6 +41,7 @@ public class MSequence extends X_AD_Sequence
/** Log Level for Next ID Call */ /** Log Level for Next ID Call */
private static final Level LOGLEVEL = Level.ALL; private static final Level LOGLEVEL = Level.ALL;
/** /**
* Get next number for Key column = 0 is Error. * Get next number for Key column = 0 is Error.
* @param AD_Client_ID client * @param AD_Client_ID client
@ -48,6 +53,30 @@ public class MSequence extends X_AD_Sequence
{ {
if (TableName == null || TableName.length() == 0) if (TableName == null || TableName.length() == 0)
throw new IllegalArgumentException("TableName missing"); throw new IllegalArgumentException("TableName missing");
//get from server
if (DB.isRemoteObjects())
{
Server server = CConnection.get().getServer();
try
{
if (server != null)
{ // See ServerBean
int id = server.getNextID(AD_Client_ID, TableName, trxName);
s_log.finest("server => " + id);
if (id < 0)
throw new DBException("No NextID");
return id;
}
s_log.log(Level.SEVERE, "AppsServer not found - " + TableName);
}
catch (RemoteException ex)
{
s_log.log(Level.SEVERE, "AppsServer error", ex);
}
// Try locally
}
int retValue = -1; int retValue = -1;
// Check AdempiereSys // Check AdempiereSys
@ -146,7 +175,8 @@ public class MSequence extends X_AD_Sequence
pstmt = null; pstmt = null;
conn.setAutoCommit(autocommit); //jz set back conn.setAutoCommit(autocommit); //jz set back
// //
// conn.close(); if (trx == null && conn != null)
conn.close();
conn = null; conn = null;
// //
break; // EXIT break; // EXIT
@ -241,6 +271,28 @@ public class MSequence extends X_AD_Sequence
if (TableName == null || TableName.length() == 0) if (TableName == null || TableName.length() == 0)
throw new IllegalArgumentException("TableName missing"); throw new IllegalArgumentException("TableName missing");
//get from server
if (DB.isRemoteObjects())
{
Server server = CConnection.get().getServer();
try
{
if (server != null)
{ // See ServerBean
String dn = server.getDocumentNo (AD_Client_ID, TableName, trxName);
s_log.finest("Server => " + dn);
if (dn != null)
return dn;
}
s_log.log(Level.SEVERE, "AppsServer not found - " + TableName);
}
catch (RemoteException ex)
{
s_log.log(Level.SEVERE, "AppsServer error", ex);
}
}
//local
// Check AdempiereSys // Check AdempiereSys
boolean adempiereSys = Ini.isPropertyBool(Ini.P_ADEMPIERESYS); boolean adempiereSys = Ini.isPropertyBool(Ini.P_ADEMPIERESYS);
if (adempiereSys && AD_Client_ID > 11) if (adempiereSys && AD_Client_ID > 11)
@ -344,7 +396,7 @@ public class MSequence extends X_AD_Sequence
if (trx == null) if (trx == null)
{ {
conn.commit(); conn.commit();
// conn.close(); conn.close();
} }
conn = null; conn = null;
} }
@ -359,8 +411,8 @@ public class MSequence extends X_AD_Sequence
if (pstmt != null) if (pstmt != null)
pstmt.close(); pstmt.close();
pstmt = null; pstmt = null;
// if (conn != null && trx == null) if (trx == null && conn != null)
// conn.close(); conn.close();
conn = null; conn = null;
} }
catch (Exception e) catch (Exception e)
@ -398,6 +450,29 @@ public class MSequence extends X_AD_Sequence
s_log.severe ("C_DocType_ID=0"); s_log.severe ("C_DocType_ID=0");
return null; return null;
} }
//get from server
if (DB.isRemoteObjects())
{
Server server = CConnection.get().getServer();
try
{
if (server != null)
{ // See ServerBean
String dn = server.getDocumentNo (C_DocType_ID, trxName);
s_log.finest("Server => " + dn);
if (dn != null)
return dn;
}
s_log.log(Level.SEVERE, "AppsServer not found - " + C_DocType_ID);
}
catch (RemoteException ex)
{
s_log.log(Level.SEVERE, "AppsServer error", ex);
}
}
//local
MDocType dt = MDocType.get (Env.getCtx(), C_DocType_ID); // wrong for SERVER, but r/o MDocType dt = MDocType.get (Env.getCtx(), C_DocType_ID); // wrong for SERVER, but r/o
if (dt != null && !dt.isDocNoControlled()) if (dt != null && !dt.isDocNoControlled())
{ {
@ -504,7 +579,7 @@ public class MSequence extends X_AD_Sequence
if (trx == null) if (trx == null)
{ {
conn.commit(); conn.commit();
// conn.close(); conn.close();
} }
conn = null; conn = null;
} }
@ -519,8 +594,8 @@ public class MSequence extends X_AD_Sequence
if (pstmt != null) if (pstmt != null)
pstmt.close(); pstmt.close();
pstmt = null; pstmt = null;
// if (conn != null && trx == null) if (trx == null && conn != null)
// conn.close(); conn.close();
conn = null; conn = null;
} }
catch (Exception e) catch (Exception e)

View File

@ -22,9 +22,9 @@ import java.net.*;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.*;
import javax.sql.*; import javax.sql.*;
import org.compiere.Adempiere;
import org.compiere.db.*; import org.compiere.db.*;
import org.compiere.interfaces.*; import org.compiere.interfaces.*;
@ -33,6 +33,11 @@ import org.compiere.interfaces.*;
* *
* @author Jorg Janke * @author Jorg Janke
* @version $Id: CPreparedStatement.java,v 1.3 2006/07/30 00:54:36 jjanke Exp $ * @version $Id: CPreparedStatement.java,v 1.3 2006/07/30 00:54:36 jjanke Exp $
* ---
* Modifications: Handle connections properly
* Reason : Due to changes brought in the connection pooling whereby the system
* no more relies upon abandoned connections.
* @author Ashley Ramdass (Posterita)
*/ */
public class CPreparedStatement extends CStatement implements PreparedStatement public class CPreparedStatement extends CStatement implements PreparedStatement
{ {
@ -844,22 +849,48 @@ public class CPreparedStatement extends CStatement implements PreparedStatement
pstmt.setBigDecimal(i+1, (BigDecimal)o); pstmt.setBigDecimal(i+1, (BigDecimal)o);
log.finest("#" + (i+1) + " - BigDecimal=" + o); log.finest("#" + (i+1) + " - BigDecimal=" + o);
} }
else if (o instanceof java.util.Date)
{
pstmt.setTimestamp(i+1, new Timestamp(((java.util.Date)o).getTime()));
log.finest("#" + (i+1) + " - Date=" + o);
}
else if (o instanceof java.sql.Date)
{
pstmt.setTimestamp(i+1, new Timestamp(((java.sql.Date)o).getTime()));
log.finest("#" + (i+1) + " - Date=" + o);
}
else else
throw new java.lang.UnsupportedOperationException ("Unknown Parameter Class=" + o.getClass()); throw new java.lang.UnsupportedOperationException ("Unknown Parameter Class=" + o.getClass());
} }
} }
catch (SQLException ex) catch (SQLException ex)
{ {
log.log(Level.SEVERE, "local", ex); log.log(Level.SEVERE, "local", ex);
try if (pstmt != null)
{ {
if (pstmt != null) try
pstmt.close(); {
pstmt = null; pstmt.close();
} }
catch (SQLException ex1) catch (Exception e)
{ {
} log.log(Level.SEVERE, "Could not close prepared statement", e);
}
}
if (conn != null && p_vo.getTrxName() == null)
{
try
{
conn.close();
}
catch (Exception e)
{
log.log(Level.SEVERE, "Could not close connection", e);
}
}
pstmt = null;
} }
return pstmt; return pstmt;
} // local_getPreparedStatement } // local_getPreparedStatement
@ -969,6 +1000,16 @@ public class CPreparedStatement extends CStatement implements PreparedStatement
pstmt.setBigDecimal(i+1, (BigDecimal)o); pstmt.setBigDecimal(i+1, (BigDecimal)o);
log.finest("#" + (i+1) + " - BigDecimal=" + o); log.finest("#" + (i+1) + " - BigDecimal=" + o);
} }
else if (o instanceof java.util.Date)
{
pstmt.setTimestamp(i+1, new Timestamp(((java.util.Date)o).getTime()));
log.finest("#" + (i+1) + " - Date=" + o);
}
else if (o instanceof java.sql.Date)
{
pstmt.setTimestamp(i+1, new Timestamp(((java.sql.Date)o).getTime()));
log.finest("#" + (i+1) + " - Date=" + o);
}
else else
throw new java.lang.UnsupportedOperationException ("Unknown Parameter Class=" + o.getClass()); throw new java.lang.UnsupportedOperationException ("Unknown Parameter Class=" + o.getClass());
} }
@ -976,25 +1017,12 @@ public class CPreparedStatement extends CStatement implements PreparedStatement
ResultSet rs = pstmt.executeQuery(); ResultSet rs = pstmt.executeQuery();
rowSet = CCachedRowSet.getRowSet(rs); rowSet = CCachedRowSet.getRowSet(rs);
rs.close(); rs.close();
pstmt.close();
pstmt = null;
} }
catch (Exception ex) catch (Exception ex)
{ {
log.log(Level.SEVERE, p_vo.toString(), ex); log.log(Level.SEVERE, p_vo.toString(), ex);
throw new RuntimeException (ex); throw new RuntimeException (ex);
} }
// Close Cursor
try
{
if (pstmt != null)
pstmt.close();
pstmt = null;
}
catch (Exception e)
{
log.log(Level.SEVERE, "close", e);
}
return rowSet; return rowSet;
} // local_getRowSet } // local_getRowSet
@ -1022,13 +1050,25 @@ public class CPreparedStatement extends CStatement implements PreparedStatement
log.log(Level.SEVERE, p_vo.toString(), ex); log.log(Level.SEVERE, p_vo.toString(), ex);
throw new RuntimeException (ex); throw new RuntimeException (ex);
} }
finally { finally
if (pstmt != null) { {
try { if (pstmt != null)
pstmt.close(); {
} catch (SQLException e) {} try
pstmt = null; {
} Connection conn = pstmt.getConnection();
pstmt.close();
if (p_vo.getTrxName() == null && !conn.isClosed())
{
conn.close();
}
}
catch (SQLException e)
{
log.log(Level.SEVERE, e.getMessage(), e);
}
pstmt = null;
}
} }
} // remote_executeUpdate } // remote_executeUpdate

View File

@ -21,7 +21,6 @@ import java.util.logging.*;
import javax.sql.*; import javax.sql.*;
import org.compiere.Adempiere;
import org.compiere.db.*; import org.compiere.db.*;
import org.compiere.interfaces.*; import org.compiere.interfaces.*;
@ -30,6 +29,12 @@ import org.compiere.interfaces.*;
* *
* @author Jorg Janke * @author Jorg Janke
* @version $Id: CStatement.java,v 1.3 2006/07/30 00:54:36 jjanke Exp $ * @version $Id: CStatement.java,v 1.3 2006/07/30 00:54:36 jjanke Exp $
* ---
* Modifications: Handle connections properly
* Close the associated connection when the statement is closed
* Reason : Due to changes brought in the connection pooling whereby the system
* no more relies upon abandoned connections.
* @author Ashley Ramdass (Posterita)
*/ */
public class CStatement implements Statement public class CStatement implements Statement
{ {
@ -742,8 +747,16 @@ public class CStatement implements Statement
*/ */
public void close () throws SQLException public void close () throws SQLException
{ {
if (p_stmt != null) if (p_stmt != null)
p_stmt.close(); {
Connection conn = p_stmt.getConnection();
p_stmt.close();
if (!conn.isClosed() && conn.getAutoCommit())
{
conn.close();
}
}
} // close } // close
/************************************************************************* /*************************************************************************
@ -770,15 +783,25 @@ public class CStatement implements Statement
log.log(Level.SEVERE, p_vo.toString(), ex); log.log(Level.SEVERE, p_vo.toString(), ex);
throw new RuntimeException (ex); throw new RuntimeException (ex);
} }
finally { finally
if (pstmt != null) {
{ if (pstmt != null)
try {
{ try
pstmt.close(); {
} catch (SQLException e){} Connection conn = pstmt.getConnection();
pstmt = null; pstmt.close();
} if (p_vo.getTrxName() == null && !conn.isClosed())
{
conn.close();
}
}
catch (SQLException e)
{
log.log(Level.SEVERE, e.getMessage(), e);
}
pstmt = null;
}
} }
} // remote_executeUpdate } // remote_executeUpdate
@ -811,15 +834,30 @@ public class CStatement implements Statement
catch (SQLException ex) catch (SQLException ex)
{ {
log.log(Level.SEVERE, "local", ex); log.log(Level.SEVERE, "local", ex);
try if (stmt != null)
{ {
if (stmt != null) try
stmt.close(); {
stmt = null; stmt.close();
} }
catch (SQLException ex1) catch (Exception e)
{ {
} log.log(Level.SEVERE, "Could not close statement", e);
}
stmt = null;
}
if (conn != null && p_vo.getTrxName() == null)
{
try
{
conn.close();
}
catch (Exception e)
{
log.log(Level.SEVERE, "Could not close connection", e);
}
}
} }
return stmt; return stmt;
} // local_getStatement } // local_getStatement
@ -926,17 +964,6 @@ public class CStatement implements Statement
log.log(Level.SEVERE, p_vo.toString(), ex); log.log(Level.SEVERE, p_vo.toString(), ex);
throw new RuntimeException (ex); throw new RuntimeException (ex);
} }
// Close Cursor
try
{
if (pstmt != null)
pstmt.close();
pstmt = null;
}
catch (Exception e)
{
log.log(Level.SEVERE, "close pstmt", e);
}
return rowSet; return rowSet;
} // local_getRowSet } // local_getRowSet

File diff suppressed because it is too large Load Diff