docs: private TransactionRecoveryResult attemptRecovery(List<ReplayLog> oldReplayLog) throws SQLException{
  		boolean tryAgain = false;
  		Throwable failedThrowable = null;
  
  		ConnectionHandle con = this.connectionHandle.get();
  		if (con == null){ // safety! 
  			throw PoolUtil.generateSQLException("ConnectionHandle is gone!", new IllegalStateException());
  		}
  		TransactionRecoveryResult recoveryResult = con.recoveryResult;
  		ConnectionHook connectionHook = con.getPool().getConfig().getConnectionHook();
  
  		int acquireRetryAttempts = con.getPool().getConfig().getAcquireRetryAttempts();
  		long acquireRetryDelay = con.getPool().getConfig().getAcquireRetryDelayInMs();
  		AcquireFailConfig acquireConfig = new AcquireFailConfig();
  		acquireConfig.setAcquireRetryAttempts(new AtomicInteger(acquireRetryAttempts));
  		acquireConfig.setAcquireRetryDelayInMs(acquireRetryDelay);
  		acquireConfig.setLogMessage("Failed to replay transaction");
  
  		Map<Object, Object> replaceTarget = new HashMap<Object, Object>();
  		do{
  			replaceTarget.clear(); 
  			// make a copy
  			for (Entry<Object, Object> entry: recoveryResult.getReplaceTarget().entrySet()){
  				replaceTarget.put(entry.getKey(), entry.getValue());
  			}
  
  			List<PreparedStatement> prepStatementTarget = new ArrayList<PreparedStatement>();
  			List<CallableStatement> callableStatementTarget = new ArrayList<CallableStatement>();
  			List<Statement> statementTarget = new ArrayList<Statement>();
  			Object result = null;
  			tryAgain = false;
  			// this connection is dead
  			con.setInReplayMode(true); // don't go in a loop of saving our saved log!
  			try{
  				con.clearStatementCaches(true);
  				con.getInternalConnection().close();
  			} catch(Throwable t){
  				// do nothing - also likely to fail here
  			}
  			try{
  				con.setInternalConnection(memorize(con.getPool().obtainInternalConnection(con), con));
  			} catch(SQLException e){
  				throw con.markPossiblyBroken(e);
  			}
  
  			con.getOriginatingPartition().trackConnectionFinalizer(con); // track this too.
  
  			for (ReplayLog replay: oldReplayLog){
  
  				// we got new connections/statement handles so replace what we've got with the new ones
  				if (replay.getTarget() instanceof Connection){
  					replaceTarget.put(replay.getTarget(), con.getInternalConnection());
  				}  else if (replay.getTarget() instanceof CallableStatement){
  					if (replaceTarget.get(replay.getTarget()) == null){
  						replaceTarget.put(replay.getTarget(), callableStatementTarget.remove(0));
  					}
  				} else if (replay.getTarget() instanceof PreparedStatement){
  					if (replaceTarget.get(replay.getTarget()) == null){
  						replaceTarget.put(replay.getTarget(), prepStatementTarget.remove(0));
  					}
  				}else if (replay.getTarget() instanceof Statement){
  					if (replaceTarget.get(replay.getTarget()) == null){
  						replaceTarget.put(replay.getTarget(), statementTarget.remove(0));
  					}
  				}
  
  
  				try {
  					// run again using the new connection/statement
  					//					result = replay.getMethod().invoke(, replay.getArgs());
  					result = runWithPossibleProxySwap(replay.getMethod(), replaceTarget.get(replay.getTarget()), replay.getArgs());
  
  					// remember what we've got last 
  					recoveryResult.setResult(result);
  
  					// if we got a new statement (eg a prepareStatement call), save it, we'll use it for our search/replace
  					if (result instanceof CallableStatement){
  						callableStatementTarget.add((CallableStatement)result);
  					} else if (result instanceof PreparedStatement){
  						prepStatementTarget.add((PreparedStatement)result);
  					} else if (result instanceof Statement){
  						statementTarget.add((Statement)result);
  					}  
  				} catch (Throwable t) {
  					// It blew up again, let's try a couple more times before giving up...
  					// call the hook, if available.
  					if (connectionHook != null){
  						tryAgain = connectionHook.onAcquireFail(t, acquireConfig);
  					} else {
  
  						logger.error("Failed to replay transaction. Sleeping for "+acquireRetryDelay+"ms and trying again. Attempts left: "+acquireRetryAttempts+". Exception: "+t.getCause() + " Message:"+t.getMessage());
  
  						try {
  							Thread.sleep(acquireRetryDelay);
  							if (acquireRetryAttempts > 0){
  								tryAgain = (--acquireRetryAttempts) != 0;
  							}
  						} catch (InterruptedException e) {
  							tryAgain=false;
  						}
  					}
  					if (!tryAgain){
  						failedThrowable = t;
  					}
  					break;
  				}
  			}
  		} while (tryAgain);
  
  		// fill last successful results
  		for (Entry<Object, Object> entry: replaceTarget.entrySet()){
  			recoveryResult.getReplaceTarget().put(entry.getKey(), entry.getValue());
  		}
  
  		for (ReplayLog replay: oldReplayLog){
  			replay.setTarget(replaceTarget.get(replay.getTarget())); // fix our log
  		}
  
  		if (failedThrowable != null){
  			throw PoolUtil.generateSQLException(failedThrowable.getMessage(), failedThrowable);
  		}
  
  
  		return recoveryResult;
  	}