@@ -134,35 +134,16 @@ public ConnectionPool(ConnectionPoolDataSource dataSource, int maxConnections, M
134134 /** Retrieves a connection from the connection pool. If all the connections
135135 * are in use, the method waits until a connection becomes available or
136136 * <code>timeout</code> seconds elapsed. When the application is finished
137- * using the connection, it must ne closed in order to return it to the pool.
137+ * using the connection, it must be closed in order to return it to the
138+ * pool.
138139 */
139140 public Connection getConnection () throws SQLException {
140- java .sql .Connection conn = getRawConnection ();
141- if (conn == null ) {
142- return null ;
143- }
144- else {
145- Connection c = new Connection ();
146- c .open (conn , database );
147- return c ;
148- }
149- }
150-
151-
152- //**************************************************************************
153- //** getRawConnection
154- //**************************************************************************
155- /** Retrieves a raw, java.sql.Connection from the connection pool. This
156- * method is called by the getConnection() method which simply wraps the
157- * java.sql.Connection into a javaxt.sql.Connection.
158- */
159- public java .sql .Connection getRawConnection () throws SQLException {
160141 long time = System .currentTimeMillis ();
161142 long timeoutTime = time + timeoutMs ;
162143 int triesWithoutDelay = getInactiveConnections () + 1 ;
163144
164145 while (true ) {
165- java . sql . Connection conn = getConnection (time , timeoutTime );
146+ Connection conn = getConnection (time , timeoutTime );
166147 if (conn != null ) {
167148 return conn ;
168149 }
@@ -306,7 +287,7 @@ public void close() throws SQLException {
306287 // Use disposeConnection to properly handle the totalConnectionCount decrement
307288 PooledConnectionWrapper wrapper ;
308289 while ((wrapper = recycledConnections .poll ()) != null ) {
309- disposeConnection (wrapper .connection );
290+ disposeConnection (wrapper .pooledConnection );
310291 }
311292
312293 connectionWrappers .clear ();
@@ -377,11 +358,11 @@ private void init(ConnectionPoolDataSource dataSource, int maxConnections, Map<S
377358 //**************************************************************************
378359 //** getConnection
379360 //**************************************************************************
380- private java . sql . Connection getConnection (long time , long timeoutTime ) {
361+ private Connection getConnection (long time , long timeoutTime ) {
381362 long rtime = Math .max (1 , timeoutTime - time );
382- java . sql . Connection conn ;
363+ Connection connection ;
383364 try {
384- conn = acquireConnection (rtime );
365+ connection = acquireConnection (rtime );
385366 }
386367 catch (SQLException e ) {
387368 return null ;
@@ -391,9 +372,11 @@ private java.sql.Connection getConnection(long time, long timeoutTime) {
391372 rtime = timeoutTime - System .currentTimeMillis ();
392373 int rtimeSecs = Math .max (1 , (int )((rtime + 999 ) / 1000 ));
393374
375+ // Validate using the underlying raw connection
376+ java .sql .Connection rawConn = connection .getConnection ();
394377 try {
395- if (conn .isValid (rtimeSecs )) {
396- return conn ;
378+ if (rawConn .isValid (rtimeSecs )) {
379+ return connection ;
397380 }
398381 }
399382 catch (SQLException e ) {
@@ -406,15 +389,15 @@ private java.sql.Connection getConnection(long time, long timeoutTime) {
406389 // and the PooledConnection has been removed from the pool, i.e. the PooledConnection will
407390 // not be added to recycledConnections when Connection.close() is called.
408391 // But to be sure that this works even with a faulty JDBC driver, we call purgeConnection().
409- purgeConnection (conn );
392+ purgeConnection (rawConn );
410393 return null ;
411394 }
412395
413396
414397 //**************************************************************************
415398 //** acquireConnection
416399 //**************************************************************************
417- private java . sql . Connection acquireConnection (long timeoutMs ) throws SQLException {
400+ private Connection acquireConnection (long timeoutMs ) throws SQLException {
418401 if (isDisposed .get ()) {
419402 throw new IllegalStateException ("Connection pool has been disposed." );
420403 }
@@ -424,7 +407,7 @@ private java.sql.Connection acquireConnection(long timeoutMs) throws SQLExceptio
424407
425408 while (System .currentTimeMillis () < timeoutTime ) {
426409 // First, try to get a recycled connection
427- java . sql . Connection recycledConn = getRecycledConnection ();
410+ Connection recycledConn = getRecycledConnection ();
428411 if (recycledConn != null ) {
429412 return recycledConn ;
430413 }
@@ -435,7 +418,7 @@ private java.sql.Connection acquireConnection(long timeoutMs) throws SQLExceptio
435418 if (currentTotal < maxConnections ) {
436419 if (totalConnections .compareAndSet (currentTotal , currentTotal + 1 )) {
437420 try {
438- java . sql . Connection conn = createNewConnection ();
421+ Connection conn = createNewConnection ();
439422 if (conn != null ) {
440423 return conn ;
441424 } else {
@@ -466,13 +449,13 @@ private java.sql.Connection acquireConnection(long timeoutMs) throws SQLExceptio
466449 //**************************************************************************
467450 //** getRecycledConnection
468451 //**************************************************************************
469- private java . sql . Connection getRecycledConnection () throws SQLException {
452+ private Connection getRecycledConnection () throws SQLException {
470453 PooledConnectionWrapper wrapper = recycledConnections .poll ();
471454 if (wrapper == null ) {
472455 return null ; // No recycled connections available
473456 }
474457
475- PooledConnection pconn = wrapper .connection ;
458+ PooledConnection pconn = wrapper .pooledConnection ;
476459
477460 // Skip all validation for very recently recycled connections (< 5 seconds)
478461 // This dramatically improves performance for high-frequency connection reuse scenarios
@@ -500,20 +483,27 @@ private java.sql.Connection getRecycledConnection() throws SQLException {
500483 }
501484 }
502485
503- // Connection is valid, update its usage time and return it
486+ // Connection is valid, update its usage time
504487 wrapper = wrapper .markUsed ();
505488 connectionWrappers .put (pconn , wrapper );
506489
507- java .sql .Connection conn ;
508490 try {
509491 connectionInTransition = pconn ;
510- activeConnections .incrementAndGet (); // Increment before getConnection() to ensure it's always counted
511- conn = pconn .getConnection ();
492+ activeConnections .incrementAndGet (); // Increment before getting connection
493+
494+ // Get a fresh logical connection from the PooledConnection
495+ java .sql .Connection rawConn = pconn .getConnection ();
496+
497+ // Re-open the javaxt.sql.Connection wrapper with the fresh logical connection
498+ // This updates the underlying connection reference without creating a new wrapper object
499+ wrapper .connection .open (rawConn , database );
500+
501+ return wrapper .connection ; // Return reused wrapper with fresh connection
512502 } catch (SQLException e ) {
513503 connectionInTransition = null ;
514- // Connection failed , decrement the activeConnections counter we just incremented
504+ // Failed , decrement the activeConnections counter we just incremented
515505 activeConnections .decrementAndGet ();
516- // Connection failed, dispose it
506+ // Dispose the wrapper
517507 connectionWrappers .remove (pconn );
518508 doPurgeConnection .set (true );
519509 try {
@@ -529,25 +519,34 @@ private java.sql.Connection getRecycledConnection() throws SQLException {
529519 } finally {
530520 connectionInTransition = null ;
531521 }
532-
533- return conn ;
534522 }
535523
536- private java .sql .Connection createNewConnection () throws SQLException {
537- PooledConnection pconn = null ;
524+
525+ //**************************************************************************
526+ //** createNewConnection
527+ //**************************************************************************
528+ private Connection createNewConnection () throws SQLException {
529+ PooledConnection pconn ;
538530 try {
539531 pconn = dataSource .getPooledConnection ();
540532 pconn .addConnectionEventListener (poolConnectionEventListener );
541- PooledConnectionWrapper wrapper = new PooledConnectionWrapper (pconn );
542- connectionWrappers .put (pconn , wrapper );
543533
544- java . sql . Connection conn ;
534+ Connection connection ;
545535 try {
546536 connectionInTransition = pconn ;
547537 activeConnections .incrementAndGet (); // Increment before getConnection() to ensure it's always counted
548- conn = pconn .getConnection ();
538+
539+ // Get raw connection and wrap it ONCE
540+ java .sql .Connection rawConn = pconn .getConnection ();
541+ connection = new Connection ();
542+ connection .open (rawConn , database );
543+
544+ // Store the pre-wrapped connection for reuse
545+ PooledConnectionWrapper wrapper = new PooledConnectionWrapper (connection , pconn );
546+ connectionWrappers .put (pconn , wrapper );
547+
549548 // totalConnections was already incremented in acquireConnection
550- return conn ;
549+ return connection ;
551550 } catch (SQLException e ) {
552551 connectionInTransition = null ;
553552 // Connection creation failed, decrement the activeConnections counter we just incremented
@@ -642,7 +641,7 @@ private void performHealthCheck() {
642641 // Process connections and re-add valid ones
643642 for (PooledConnectionWrapper w : toCheck ) {
644643 if (w .isIdle (connectionIdleTimeoutMs ) || w .isExpired (connectionMaxAgeMs )) {
645- disposeConnection (w .connection );
644+ disposeConnection (w .pooledConnection );
646645 removedCount ++;
647646 log ("Removed " + (w .isExpired (connectionMaxAgeMs ) ? "expired" : "idle" ) +
648647 " connection from pool. Age: " + (now - w .createdTime ) + "ms" );
@@ -694,9 +693,20 @@ private void performHealthCheck() {
694693 pconn .addConnectionEventListener (poolConnectionEventListener );
695694
696695 if (validateConnection (pconn )) {
697- PooledConnectionWrapper w = new PooledConnectionWrapper (pconn );
696+ // Create and wrap connection for warm-up
697+ java .sql .Connection rawConn = pconn .getConnection ();
698+ Connection connection = new Connection ();
699+ connection .open (rawConn , database );
700+
701+ // Store the wrapper (but don't add to recycled yet - it's active)
702+ PooledConnectionWrapper w = new PooledConnectionWrapper (connection , pconn );
698703 connectionWrappers .put (pconn , w );
699- recycledConnections .offer (w );
704+
705+ // Close the connection to recycle it
706+ // This will trigger connectionClosed event which calls recycleConnection()
707+ // recycleConnection() will add it to the recycled queue
708+ rawConn .close ();
709+
700710 currentRecycled ++;
701711 total = currentActive + currentRecycled ;
702712 log ("Pool warm-up: added connection " + currentRecycled + "/" + minConnections );
@@ -812,13 +822,13 @@ private void recycleConnection (PooledConnection pconn) {
812822 PooledConnectionWrapper wrapper = connectionWrappers .get (pconn );
813823 if (wrapper != null ) {
814824 // Update the wrapper with current usage time and add to recycled connections
825+ // The javaxt.sql.Connection wrapper is reused - no new object creation!
815826 wrapper = wrapper .markUsed ();
816827 recycledConnections .offer (wrapper );
817828 }
818829 else {
819- // Fallback: create new wrapper if not found (shouldn't happen in normal operation)
820- wrapper = new PooledConnectionWrapper (pconn );
821- recycledConnections .offer (wrapper );
830+ // This shouldn't happen in normal operation - log a warning
831+ log ("Warning: Wrapper not found for PooledConnection during recycle" );
822832 }
823833
824834 // Connection successfully recycled
@@ -846,7 +856,7 @@ private void disposeConnection (PooledConnection pconn) {
846856 // Try to remove from recycled connections
847857 boolean foundInRecycled = false ;
848858 for (PooledConnectionWrapper wrapper : recycledConnections ) {
849- if (wrapper .connection == pconn ) {
859+ if (wrapper .pooledConnection == pconn ) {
850860 if (recycledConnections .remove (wrapper )) {
851861 foundInRecycled = true ;
852862 }
@@ -885,8 +895,8 @@ private void disposeConnection (PooledConnection pconn) {
885895 //** log
886896 //**************************************************************************
887897 private void log (String msg ) {
888- String s = "ConnectionPool: " +msg ;
889- try {
898+ String s = "ConnectionPool: " +msg ;
899+ try {
890900 if (logWriter == null ) {
891901 //System.err.println(s);
892902 }
@@ -943,18 +953,21 @@ public void connectionErrorOccurred (ConnectionEvent event) {
943953 /** Wrapper class to track connection metadata
944954 */
945955 private static class PooledConnectionWrapper {
946- final PooledConnection connection ;
956+ final Connection connection ;
957+ final PooledConnection pooledConnection ;
947958 final long createdTime ;
948959 final long lastUsedTime ;
949960
950- PooledConnectionWrapper (PooledConnection connection ) {
961+ PooledConnectionWrapper (Connection connection , PooledConnection pooledConnection ) {
951962 this .connection = connection ;
963+ this .pooledConnection = pooledConnection ;
952964 this .createdTime = System .currentTimeMillis ();
953965 this .lastUsedTime = System .currentTimeMillis ();
954966 }
955967
956- PooledConnectionWrapper (PooledConnection connection , long createdTime , long lastUsedTime ) {
968+ PooledConnectionWrapper (Connection connection , PooledConnection pooledConnection , long createdTime , long lastUsedTime ) {
957969 this .connection = connection ;
970+ this .pooledConnection = pooledConnection ;
958971 this .createdTime = createdTime ;
959972 this .lastUsedTime = lastUsedTime ;
960973 }
@@ -968,7 +981,7 @@ boolean isExpired(long maxAgeMs) {
968981 }
969982
970983 PooledConnectionWrapper markUsed () {
971- return new PooledConnectionWrapper (connection , createdTime , System .currentTimeMillis ());
984+ return new PooledConnectionWrapper (connection , pooledConnection , createdTime , System .currentTimeMillis ());
972985 }
973986 }
974987
0 commit comments