r10000 - in helma/helma/trunk/src/helma: framework/core main objectmodel/db
[email protected] Mon, 30 Nov 2009 11:58:34 +0100 (CET)
| Newsgroups | gmane.comp.java.helma.cvs |
|---|---|
| Message-ID | <20091130105834.4CE983D0E2@mia> |
Author: hannes
Date: 2009-11-30 11:58:34 +0100 (Mon, 30 Nov 2009)
New Revision: 10000
Added:
helma/helma/trunk/src/helma/objectmodel/db/DbConnection.java
Modified:
helma/helma/trunk/src/helma/framework/core/Application.java
helma/helma/trunk/src/helma/main/Server.java
helma/helma/trunk/src/helma/objectmodel/db/DbSource.java
helma/helma/trunk/src/helma/objectmodel/db/Transactor.java
Log:
Refactor db connection pooling: Use connection names instead of connection properties as has keys, introduce new DbConnection wrapper class and a serial-id flag in DbSource to validate connections.
Details at http://dev.helma.org/trac/helma/changeset/10000
Modified: helma/helma/trunk/src/helma/framework/core/Application.java
===================================================================
--- helma/helma/trunk/src/helma/framework/core/Application.java 2009-11-27 15:17:33 UTC (rev 9999)
+++ helma/helma/trunk/src/helma/framework/core/Application.java 2009-11-30 10:58:34 UTC (rev 10000)
@@ -1527,6 +1527,13 @@
}
/**
+ * Log a generic application debug message
+ */
+ public void logDebug(String msg) {
+ getEventLog().debug(msg);
+ }
+
+ /**
* Log an application access
*/
public void logAccess(String msg) {
Modified: helma/helma/trunk/src/helma/main/Server.java
===================================================================
--- helma/helma/trunk/src/helma/main/Server.java 2009-11-27 15:17:33 UTC (rev 9999)
+++ helma/helma/trunk/src/helma/main/Server.java 2009-11-30 10:58:34 UTC (rev 10000)
@@ -417,7 +417,6 @@
dbProps = new ResourceProperties();
dbProps.setIgnoreCase(false);
dbProps.addResource(new FileResource(file));
- DbSource.setDefaultProps(dbProps);
// read apps.properties file
String appsPropfile = sysProps.getProperty("appsPropFile");
Added: helma/helma/trunk/src/helma/objectmodel/db/DbConnection.java
Modified: helma/helma/trunk/src/helma/objectmodel/db/DbSource.java
===================================================================
--- helma/helma/trunk/src/helma/objectmodel/db/DbSource.java 2009-11-27 15:17:33 UTC (rev 9999)
+++ helma/helma/trunk/src/helma/objectmodel/db/DbSource.java 2009-11-30 10:58:34 UTC (rev 10000)
@@ -27,20 +27,18 @@
import java.util.Hashtable;
/**
- * This class describes a releational data source (URL, driver, user and password).
+ * This class describes a relational data source (URL, driver, user and password).
*/
public class DbSource {
- private static ResourceProperties defaultProps = null;
- private Properties conProps;
private String name;
- private ResourceProperties props, subProps;
+ private int serialId = 0;
+ private ResourceProperties props;
protected String url;
private String driver;
+ private Properties conProps;
private boolean isOracle, isMySQL, isPostgreSQL, isH2;
private long lastRead = 0L;
private Hashtable dbmappings = new Hashtable();
- // compute hashcode statically because it's expensive and we need it often
- private int hashcode;
// thread local connection holder for non-transactor threads
private ThreadLocal connection;
@@ -68,56 +66,47 @@
*/
public synchronized Connection getConnection()
throws ClassNotFoundException, SQLException {
- Connection con;
+ DbConnection con;
Transactor tx = Transactor.getInstance();
+ if (props.lastModified() != lastRead) {
+ init();
+ }
if (tx != null) {
- con = tx.getConnection(this);
+ con = tx.getDbConnection(name, serialId);
} else {
- con = getThreadLocalConnection();
+ con = getThreadLocalDbConnection();
}
- boolean fileUpdated = props.lastModified() > lastRead ||
- (defaultProps != null && defaultProps.lastModified() > lastRead);
+ if (con == null) {
+ con = new DbConnection(DriverManager.getConnection(url, conProps), serialId);
- if (con == null || con.isClosed() || fileUpdated) {
- init();
- con = DriverManager.getConnection(url, conProps);
-
// If we wanted to use SQL transactions, we'd set autoCommit to
// false here and make commit/rollback invocations in Transactor methods;
// System.err.println ("Created new Connection to "+url);
if (tx != null) {
- tx.registerConnection(this, con);
+ tx.registerConnection(name, con);
} else {
connection.set(con);
}
}
- return con;
+ return con.getConnection();
}
/**
* Used for connections not managed by a Helma transactor
* @return a thread local tested connection, or null
*/
- private Connection getThreadLocalConnection() {
+ private DbConnection getThreadLocalDbConnection() {
if (connection == null) {
connection = new ThreadLocal();
return null;
}
- Connection con = (Connection) connection.get();
- if (con != null) {
- // test if connection is still ok
- try {
- Statement stmt = con.createStatement();
- stmt.execute("SELECT 1");
- stmt.close();
- } catch (SQLException sx) {
- try {
- con.close();
- } catch (SQLException ignore) {/* nothing to do */}
- return null;
- }
+ DbConnection con = (DbConnection) connection.get();
+ if (con != null && !con.isValid(serialId)) {
+ con.close();
+ connection.remove();
+ return null;
}
return con;
}
@@ -142,13 +131,10 @@
* @throws ClassNotFoundException if the JDBC driver couldn't be loaded
*/
private synchronized void init() throws ClassNotFoundException {
- lastRead = (defaultProps == null) ? props.lastModified()
- : Math.max(props.lastModified(),
- defaultProps.lastModified());
+ lastRead = props.lastModified();
+ serialId ++;
// refresh sub-properties for this DbSource
- subProps = props.getSubProperties(name + '.');
- // use properties hashcode for ourselves
- hashcode = subProps.hashCode();
+ ResourceProperties subProps = props.getSubProperties(name + '.');
// get JDBC URL and driver class name
url = subProps.getProperty("url");
driver = subProps.getProperty("driver");
@@ -213,15 +199,6 @@
}
/**
- * Set the default (server-wide) properties
- *
- * @param props server default db.properties
- */
- public static void setDefaultProps(ResourceProperties props) {
- defaultProps = props;
- }
-
- /**
* Check if this DbSource represents an Oracle database
*
* @return true if we're using an oracle JDBC driver
@@ -278,17 +255,4 @@
return (DbMapping) dbmappings.get(tablename.toUpperCase());
}
- /**
- * Returns a hash code value for the object.
- */
- public int hashCode() {
- return hashcode;
- }
-
- /**
- * Indicates whether some other object is "equal to" this one.
- */
- public boolean equals(Object obj) {
- return obj instanceof DbSource && subProps.equals(((DbSource) obj).subProps);
- }
}
Modified: helma/helma/trunk/src/helma/objectmodel/db/Transactor.java
===================================================================
--- helma/helma/trunk/src/helma/objectmodel/db/Transactor.java 2009-11-27 15:17:33 UTC (rev 9999)
+++ helma/helma/trunk/src/helma/objectmodel/db/Transactor.java 2009-11-30 10:58:34 UTC (rev 10000)
@@ -234,37 +234,38 @@
/**
* Register a db connection with this transactor thread.
- * @param src the db source
+ * @param name the db source name
* @param con the connection
*/
- public void registerConnection(DbSource src, Connection con) {
- sqlConnections.put(src, con);
+ public void registerConnection(String name, DbConnection con) {
+ DbConnection previous = (DbConnection) sqlConnections.put(name, con);
+ if (previous != null) {
+ nmgr.app.logEvent("Closing previous connection " + con);
+ previous.close();
+ }
// we assume a freshly created connection is ok.
- testedConnections.put(src, new Long(System.currentTimeMillis()));
+ testedConnections.put(name, new Long(System.currentTimeMillis()));
}
/**
* Get a db connection that was previously registered with this transactor thread.
- * @param src the db source
- * @return the connection
+ * @param name the db source name
+ * @param serialId the current serial id of the db source definition, used for validation
+ * @return the connection, or null if no valid connection is available
*/
- public Connection getConnection(DbSource src) {
- Connection con = (Connection) sqlConnections.get(src);
- Long tested = (Long) testedConnections.get(src);
+ public DbConnection getDbConnection(String name, int serialId) {
+ DbConnection con = (DbConnection) sqlConnections.get(name);
+ Long tested = (Long) testedConnections.get(name);
long now = System.currentTimeMillis();
- if (con != null && (tested == null || now - tested.longValue() > 60000)) {
- // Check if the connection is still alive by executing a simple statement.
- try {
- Statement stmt = con.createStatement();
- stmt.execute("SELECT 1");
- stmt.close();
- testedConnections.put(src, new Long(now));
- } catch (SQLException sx) {
- try {
- con.close();
- } catch (SQLException ignore) {/* nothing to do */}
- return null;
- }
+ // Check if the connection is still valid
+ if (con != null
+ && (tested == null || now - tested.longValue() > 60000)
+ && !con.isValid(serialId)) {
+ nmgr.app.logEvent("Closing cached connection " + con);
+ sqlConnections.remove(name);
+ testedConnections.remove(name);
+ con.close();
+ return null;
}
return con;
}
@@ -529,12 +530,11 @@
if (sqlConnections != null) {
for (Iterator i = sqlConnections.values().iterator(); i.hasNext();) {
try {
- Connection con = (Connection) i.next();
-
+ DbConnection con = (DbConnection) i.next();
con.close();
nmgr.app.logEvent("Closing DB connection: " + con);
- } catch (Exception ignore) {
- // exception closing db connection, ignore
+ } catch (Exception x) {
+ nmgr.app.logEvent("Error closing DB connection: " + x);
}
}