Have the depot retry on transient failures.

Untested, until tomorrow morning!
This commit is contained in:
Ray Greenwell
2006-11-08 00:30:10 +00:00
parent e60dd15486
commit 00aa0f2d96
@@ -85,18 +85,7 @@ public class PersistenceContext
throws PersistenceException throws PersistenceException
{ {
// TODO: check the cache using query.getKey() // TODO: check the cache using query.getKey()
return (T) invoke(query, null, true);
// TODO: retry query on transient failure
Connection conn = _conprov.getConnection(_ident, true);
try {
return query.invoke(conn);
} catch (SQLException sqe) {
throw new PersistenceException("Query failure " + query, sqe);
} finally {
_conprov.releaseConnection(_ident, true, conn);
}
} }
/** /**
@@ -107,26 +96,76 @@ public class PersistenceContext
{ {
// TODO: invalidate the cache using the modifier's key // TODO: invalidate the cache using the modifier's key
// TODO: retry query on transient failure int result = (Integer) invoke(null, modifier, true);
Connection conn = _conprov.getConnection(_ident, false); // TODO: (optionally) cache the results of the modifier
return result;
}
/**
* Internal invoke method that takes care of transient retries
* for both queries and modifiers.
*/
protected <T> Object invoke (
Query<T> query, Modifier modifier, boolean retryOnTransientFailure)
throws PersistenceException
{
boolean isReadOnlyQuery = (query != null);
Connection conn = _conprov.getConnection(_ident, isReadOnlyQuery);
try { try {
int result = modifier.invoke(conn); if (isReadOnlyQuery) {
// TODO: (optionally) cache the results of the modifier // if this becomes more complex than this single statement,
return result; // then this should turn into a method call that contains
// the complexity
return query.invoke(conn);
} else {
// if this becomes more complex than this single statement,
// then this should turn into a method call that contains
// the complexity
return modifier.invoke(conn);
}
} catch (SQLException sqe) { } catch (SQLException sqe) {
// convert this exception to a DuplicateKeyException if appropriate
String msg = sqe.getMessage(); if (!isReadOnlyQuery) {
if (msg != null && msg.indexOf("Duplicate entry") != -1) { // convert this exception to a DuplicateKeyException if
throw new DuplicateKeyException(msg); // appropriate
String msg = sqe.getMessage();
if (msg != null && msg.indexOf("Duplicate entry") != -1) {
throw new DuplicateKeyException(msg);
}
}
if (retryOnTransientFailure && isTransientException(sqe)) {
Log.info("Transient failure executing operation, " +
"retrying [error=" + sqe + "].");
} else { } else {
throw new PersistenceException( String msg = isReadOnlyQuery ? "Query failure " + query
"Modifier failure " + modifier, sqe); : "Modifier failure " + modifier;
throw new PersistenceException(msg, sqe);
} }
} finally { } finally {
_conprov.releaseConnection(_ident, false, conn); _conprov.releaseConnection(_ident, isReadOnlyQuery, conn);
} }
// if we got here, we want to retry a transient failure
return invoke(query, modifier, false);
}
/**
* Check whether the specified exception is a transient failure
* that can be retried.
*/
protected boolean isTransientException (SQLException sqe)
{
// TODO: this is MySQL specific. This was snarfed from MySQLLiaison.
String msg = sqe.getMessage();
return (msg != null &&
(msg.indexOf("Lost connection") != -1 ||
msg.indexOf("link failure") != -1 ||
msg.indexOf("Broken pipe") != -1));
} }
protected String _ident; protected String _ident;