Date: Friday, February 24, 2006 @ 12:56:41
Author: gilles
Path: /cvsroot/carob/carob
Modified: include/Connection.hpp (1.61 -> 1.62) src/Connection.cpp (1.69
-> 1.70) src/ControllerConnectPolicy.cpp (1.10 -> 1.11)
test/10-Connection/TestConnect.cpp (1.4 -> 1.5)
Connection:
- Changed Connection constructor behavior: now connects to other controllers in
the connection policy list in case of failure + fixed exceptions thrown
- Extracted closeSocket() new function from close (for reconnection to be able
to close only the socket)
- Added reconnectOrDie() function that tries reconnection on all non suspect
controllers
- Changed reconnect() to take these two functions into account
- Added ConnectionException to the functions that do reconnection
- Removed setConnectionParametersOnRequest() call from reconnection loop (the
connection doesn't change => do it once for all)
- Fixed FO_TRY_NTIMES macro to be more readable
- Added logging
ControllerConnectPolicy:
- Added forgotten call to updateSuspectList() !
- Added logging for ping socket creation
TestConnect:
- Connection change took into account (authentication exception instead of
connection exception)
------------------------------------+
include/Connection.hpp | 54 +++++--
src/Connection.cpp | 250 ++++++++++++++++++++++-------------
src/ControllerConnectPolicy.cpp | 5
test/10-Connection/TestConnect.cpp | 4
4 files changed, 208 insertions(+), 105 deletions(-)
Index: carob/include/Connection.hpp
diff -u carob/include/Connection.hpp:1.61 carob/include/Connection.hpp:1.62
--- carob/include/Connection.hpp:1.61 Fri Feb 17 17:15:45 2006
+++ carob/include/Connection.hpp Fri Feb 24 12:56:41 2006
@@ -171,7 +171,7 @@
void setAutoCommit(bool autoCommit)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
- UnexpectedException);
+ ConnectionException, UnexpectedException);
/**
* Makes all changes made since the previous commit/rollback permanent and
* releases any database locks currently held by the <code>Connection</code>.
@@ -183,7 +183,8 @@
* @see Connection#setAutoCommit(boolean)
*/
void commit() throw (SocketIOException, DriverException,
- ProtocolException, UnexpectedException);
+ ProtocolException, ConnectionException,
+ UnexpectedException);
/**
* Drops all changes made since the previous commit/rollback and releases any
* database locks currently held by this connection. If the connection was in
@@ -193,7 +194,8 @@
* @see Connection#commit()
*/
void rollback() throw (SocketIOException, DriverException,
- ProtocolException, UnexpectedException);
+ ProtocolException, ConnectionException,
+ UnexpectedException);
/**
* SQL statements without parameters are normally executed using
* <code>Statement</code> objects. If the same SQL statement is executed
@@ -232,7 +234,8 @@
DriverResultSet* statementExecuteQuery(RequestWithResultSetParameters&
request)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
- NotImplementedException, UnexpectedException);
+ NotImplementedException, ConnectionException,
+ UnexpectedException);
/**
* Performs a write request and return the number of rows affected.
*
@@ -243,7 +246,7 @@
int statementExecuteUpdate(Request& r)
throw (SocketIOException, BackendException,
ControllerException, ProtocolException,
- UnexpectedException);
+ ConnectionException, UnexpectedException);
/**
* Calls a request that returns a list of results.
* This list is returned as a copy (ie. not a pointer) because it contains
@@ -258,7 +261,8 @@
RequestWithResultSetParameters&
request)
throw (SocketIOException,
BackendException, ControllerException,
- ProtocolException,
UnexpectedException);
+ ProtocolException, ConnectionException,
+ UnexpectedException);
/**
* Performs a write request and returns the auto-generated keys
*
@@ -273,7 +277,8 @@
Request &request)
throw (SocketIOException,
BackendException,ControllerException,
- ProtocolException,
UnexpectedException);
+ ProtocolException, ConnectionException,
+ UnexpectedException);
/**
* Closes the remote ResultSet given its cursor name.
*
@@ -326,7 +331,8 @@
DriverResultSet* preparedStatementGetMetaData(const std::wstring
&sqlTemplate)
throw (SocketIOException, BackendException,
ProtocolException, ControllerException,
- NotImplementedException, UnexpectedException);
+ NotImplementedException, ConnectionException,
+ UnexpectedException);
protected:
/**
@@ -360,14 +366,20 @@
AuthenticationException, UnexpectedException);
/**
- * Closes a connection by sending appropriate commands to the controller.
+ * Deletes all statements created by this connection and closes the socket
+ * to the connected controller.
* If an error occurs while closing, just logs the error and returns false,
* but does not throw any exception.
- * Called mainly by the connection destructor.
* @return true if the connection has been closed without errors
*/
bool close();
-
+ /**
+ * Closes the socket by sending appropriate commands to the controller.
+ * If an error occurs while closing, just logs the error and returns false,
+ * but does not throw any exception.
+ * @return true if the connection has been closed without errors
+ */
+ bool closeSocket();
/**
* Serializes a write request on the output stream by sending only the needed
* parameters to reconstruct it on the controller
@@ -437,7 +449,8 @@
*/
void beginTransactionIfNeeded() throw (SocketIOException,
BackendException, ControllerException,
- ProtocolException, UnexpectedException);
+ ProtocolException, ConnectionException,
+ UnexpectedException);
/**
* Set the autocommit mode and read-only status on this request.
@@ -592,10 +605,23 @@
* controller chosen using the policy specified in the connection parameters
* of this connection.
*
+ * @throw ConnectionException if the next controller (get from connection
+ * policy) is also down
* @throw NoMoreControllerException if no valid controller left
- * @throw DriverException if an other error occured
+ * @throw DriverException if controllers are misconfigurated
+ */
+ void tryToReconnect() throw (NoMoreControllerException,
+ DriverException, UnexpectedException);
+ /**
+ * Calls reconnect until :
+ * - success
+ * - NoMoreControllerException
+ * - Other unrecoverable error
+ *
+ * @throw ConnectionException if no valid controller is left
+ * @throw DriverException if controllers are misconfigurated
*/
- void reconnect() throw (NoMoreControllerException,
+ void reconnectOrDie() throw (ConnectionException,
DriverException, UnexpectedException);
/**
* Forbids Connection creation that would lead to unexpected state.
Index: carob/src/Connection.cpp
diff -u carob/src/Connection.cpp:1.69 carob/src/Connection.cpp:1.70
--- carob/src/Connection.cpp:1.69 Tue Feb 21 17:51:43 2006
+++ carob/src/Connection.cpp Fri Feb 24 12:56:41 2006
@@ -42,25 +42,22 @@
// When a SocketIOException occurs between these to macros, sleep and try to
// reconnect(). Sleeping time depends on the retry #. Only N retries are
// performed
-#define FO_TRY_NTIMES(N) for (int foCnt=0; foCnt<N; foCnt++) { try {
-#define FO_CATCH_NTIMES break; /* if no exception, get out of the for */\
-} catch (SocketIOException sioe) { ::sleep(static_cast<int>(foCnt*0.5));
reconnect(); } }
-
-/* This gives:
-for (int foCnt=0; foCnt<N; foCnt++)
-{
- try
- {
- ***CODE***
- break; // if no exception, get out of the for
- }
- catch (SocketIOException sioe)
- {
- ::sleep(foCnt*0.5); // 0s the 1st and 2nd time, 1s the 3rd and 4th...
- reconnect();
- }
+#define FO_TRY_NTIMES(N)\
+for (int foCnt=0; foCnt<N; foCnt++)\
+{\
+ try\
+ {\
+ /* Code to monitor will go here */
+#define FO_CATCH_NTIMES\
+ break; /* if no exception, get out of the for */\
+ }\
+ catch (SocketIOException sioe)\
+ {\
+ ::sleep(static_cast<int>(foCnt*0.5)); /* sleep incrementally */\
+ reconnectOrDie();\
+ }\
}
-*/
+
Connection::Connection(const ConnectionParameters& prms)
throw (DriverException, ConnectionException, AuthenticationException,
UnexpectedException) :
@@ -85,25 +82,52 @@
throw DriverException(L"Unsupported connection policy #" +
toWString(parameters.getConnectPolicy()));
}
persistent_connection = parameters.getPersistentConnection();
- try
+ while (isClosed)
{
- if (connect_policy_ptr == NULL)
- throw DriverException(L"Connection policy error. Aborting.");
- connected_controller = connect_policy_ptr->getController();
-
- //Do the authentication stuff, then receive ack and other params
- if (initConnection() && finalizeConnect())
+ try
{
- isClosed = false;
+ if (connect_policy_ptr == NULL)
+ throw DriverException(L"Connection policy error. Aborting.");
+ connected_controller = connect_policy_ptr->getController();
+
+ //Do the authentication stuff, then receive ack and other params
+ if (initConnection() && finalizeConnect())
+ {
+ isClosed = false;
+ }
+ }
+ // SocketIO and connection exceptions indicate dead controller => try to
+ // connect to the next one in the controller list
+ catch (SocketIOException sioe)
+ {
+ //Do some clean up
+ delete driverSocketPtr; driverSocketPtr = NULL;
+ //suspect failing controller and try next one
+ connect_policy_ptr->suspectControllerOfFailure(connected_controller);
+ }
+ catch (ConnectionException ce)
+ {
+ //Do some clean up
+ delete driverSocketPtr; driverSocketPtr = NULL;
+ //suspect failing controller and try next one
+ connect_policy_ptr->suspectControllerOfFailure(connected_controller);
+ }
+ catch (NoMoreControllerException nmce)
+ {
+ // Clean all: we are in constructor, destructor won't be called !
+ delete driverSocketPtr; driverSocketPtr = NULL;
+ delete connect_policy_ptr; connect_policy_ptr = NULL;
+ //
+ throw (ConnectionException(nmce.description()));
+ }
+ // Other exceptions must be reported to the user
+ catch (...)
+ {
+ // Clean all: we are in constructor, destructor won't be called !
+ delete driverSocketPtr; driverSocketPtr = NULL;
+ delete connect_policy_ptr; connect_policy_ptr = NULL;
+ throw;
}
- }
- catch (...)
- {
- //Do some clean up: we are in constructor so if we throw an exception, the
- //destructor will never be called...
- delete driverSocketPtr; driverSocketPtr = NULL;
- delete connect_policy_ptr; connect_policy_ptr = NULL;
- throw;
}
}
@@ -304,12 +328,15 @@
bool Connection::close()
{
- wstring fctName(L"Connection::closeConnection");
+ wstring fctName(L"Connection::close");
//Wait until other methods/Commands are done
LockScope ls(&connectionCS);
isClosed = true;
+
+ if (isDebugEnabled())
+ logDebug(fctName, L"Deleting statements created by this connection");
//delete all statement created by this connection
for (std::list<Statement*>::iterator iter = created_statements.begin();
iter != created_statements.end(); iter++)
@@ -318,13 +345,21 @@
}
created_statements.clear();
+ return closeSocket();
+}
+
+bool Connection::closeSocket()
+{
+ wstring fctName(L"Connection::closeSocket");
+ bool closeOK = false;
+
if (driverSocketPtr == NULL)
{
return false;
}
- bool closeOK = false;
+
if (isDebugEnabled())
- logDebug(fctName, L"Closing connection");
+ logDebug(fctName, L"Closing socket to controller");
try
{
// Try to cleanly close the connection (also on controller side)
@@ -334,7 +369,7 @@
catch (...)
{
if (isWarnEnabled())
- logWarn(fctName, L"Could not warn controller we are closing connection");
+ logWarn(fctName, L"Could not inform controller we are closing
connection");
}
try
{
@@ -356,7 +391,7 @@
void Connection::setAutoCommit(bool autoCommitPrm)
throw (SocketIOException, BackendException, ControllerException,
- ProtocolException, UnexpectedException)
+ ProtocolException, ConnectionException, UnexpectedException)
{
wstring fctName(L"Connection::setAutoCommit");
@@ -408,7 +443,8 @@
}
void Connection::beginTransactionIfNeeded() throw (SocketIOException,
-BackendException, ControllerException, ProtocolException, UnexpectedException)
+ BackendException, ControllerException, ProtocolException,
+ ConnectionException, UnexpectedException)
{
if (mustBeginTransaction)
{
@@ -431,7 +467,7 @@
}
void Connection::commit() throw (SocketIOException, DriverException,
- ProtocolException, UnexpectedException)
+ ProtocolException, ConnectionException, UnexpectedException)
{
wstring fctName(L"Connection::commit");
@@ -464,7 +500,7 @@
}
catch (SocketIOException e)
{ // Connection failed, try to reconnect and re-exec the commit
- reconnect();
+ reconnectOrDie();
int64_t acknowledgedTransactionId = retrieveCommitResult();
if (acknowledgedTransactionId != transactionId)
{
@@ -481,7 +517,7 @@
}
void Connection::rollback() throw (SocketIOException, DriverException,
- ProtocolException, UnexpectedException)
+ ProtocolException, ConnectionException, UnexpectedException)
{
wstring fctName(L"Connection::rollback");
@@ -515,7 +551,7 @@
}
catch (SocketIOException e)
{ // Connection failed, try to reconnect and re-exec the rollback
- reconnect();
+ reconnectOrDie();
int64_t acknowledgedTransactionId = retrieveRollbackResult();
if (acknowledgedTransactionId != transactionId)
{
@@ -559,7 +595,8 @@
DriverResultSet* Connection::preparedStatementGetMetaData(const wstring
&sqlTemplate)
throw (SocketIOException, BackendException, ControllerException,
- ProtocolException, NotImplementedException, UnexpectedException)
+ ProtocolException, NotImplementedException, ConnectionException,
+ UnexpectedException)
{
checkIfConnected();
wstring fctName(L"Connection::PreparedStatementGetMetaData");
@@ -588,7 +625,8 @@
DriverResultSet* Connection::statementExecuteQuery
(RequestWithResultSetParameters& request)
throw (SocketIOException, BackendException, ControllerException,
- ProtocolException, NotImplementedException, UnexpectedException)
+ ProtocolException, NotImplementedException, ConnectionException,
+ UnexpectedException)
{
wstring fctName(L"Connection::statementExecuteQuery");
@@ -597,11 +635,11 @@
checkIfConnected();
beginTransactionIfNeeded();
+ setConnectionParametersOnRequest(request);
DriverResultSet* retVal = NULL;
FO_TRY_NTIMES(RECONNECT_RETRIES)
- setConnectionParametersOnRequest(request);
if (isDebugEnabled())
logDebug(fctName, L"Sending read request " +
static_cast<wstring>(request));
sendCommand(*driverSocketPtr, StatementExecuteQuery);
@@ -614,7 +652,7 @@
int Connection::statementExecuteUpdate(Request& request)
throw (SocketIOException, BackendException, ControllerException,
- ProtocolException, UnexpectedException)
+ ProtocolException, ConnectionException, UnexpectedException)
{
wstring fctName(L"Connection::statementExecuteUpdate");
@@ -622,17 +660,18 @@
checkIfConnected();
beginTransactionIfNeeded();
+ setConnectionParametersOnRequest(request);
int controllerResponse = -1;
FO_TRY_NTIMES(RECONNECT_RETRIES)
- setConnectionParametersOnRequest(request);
if (isDebugEnabled())
logDebug(fctName, L"Sending write request " +
static_cast<wstring>(request));
sendCommand(*driverSocketPtr, StatementExecuteUpdate);
writeRequestOnStream(request);
request.setId(receiveLongOrException());
FO_CATCH_NTIMES
+
// At this point, the request id has been received, let's retrieve the
// update count
try
@@ -652,26 +691,27 @@
std::list<ResultSetOrUpdateCount> Connection::statementExecute(
RequestWithResultSetParameters& request) throw (SocketIOException,
BackendException, ControllerException, ProtocolException,
- UnexpectedException)
+ ConnectionException, UnexpectedException)
{
wstring fctName(L"Connection::statementExecute");
LockScope ls(&connectionCS);
checkIfConnected();
beginTransactionIfNeeded();
+ setConnectionParametersOnRequest(request);
std::list<ResultSetOrUpdateCount> results;
FO_TRY_NTIMES(RECONNECT_RETRIES)
if (isDebugEnabled())
logDebug(fctName, L"Sending request " + static_cast<wstring>(request));
- setConnectionParametersOnRequest(request);
if (!autoCommit)
writeExecutedInTransaction = true;
sendCommand(*driverSocketPtr, StatementExecute);
request.sendToStream(*driverSocketPtr);
request.setId(receiveLongOrException());
FO_CATCH_NTIMES
+
try
{
results = fetchMultipleResultsFromStream();
@@ -701,7 +741,8 @@
std::list<ResultSetOrUpdateCount> Connection::statementExecuteUpdateWithKeys(
Request &request) throw (SocketIOException, BackendException,
- ControllerException, ProtocolException, UnexpectedException)
+ ControllerException, ProtocolException, ConnectionException,
+ UnexpectedException)
{
wstring fctName(L"Connection::statementExecuteUpdateWithKeys");
@@ -709,13 +750,13 @@
checkIfConnected();
beginTransactionIfNeeded();
+ setConnectionParametersOnRequest(request);
std::list<ResultSetOrUpdateCount> result;
for (int failuresCnt=0; failuresCnt<RECONNECT_RETRIES; failuresCnt++)
{ // this for is in the case we were disconnected and the controller did not
// get the update request
FO_TRY_NTIMES(RECONNECT_RETRIES)
- setConnectionParametersOnRequest(request);
if (isDebugEnabled())
logDebug(fctName, L"Executing write request with keys: "
+ static_cast<wstring>(request));
@@ -1040,15 +1081,49 @@
return results;
}
-void Connection::reconnect() throw (NoMoreControllerException, DriverException,
- UnexpectedException)
+void Connection::reconnectOrDie() throw (ConnectionException,
+ DriverException, UnexpectedException)
{
- wstring fctName(L"Connection::reconnect");
+ wstring fctName(L"Connection::reconnectOrDie");
+ bool reconnected = false;
+ while (!reconnected)
+ {
+ try
+ {
+ tryToReconnect();
+ reconnected = true;
+ }
+ catch (ConnectionException ce)
+ {
+ if (isDebugEnabled())
+ logDebug(fctName, L"Controller "
+ + static_cast<wstring>(connected_controller)
+ + L" seams to be down - giving it a last chance...");
+ }
+ catch (NoMoreControllerException nmce)
+ {
+ throw (ConnectionException(nmce.description()));
+ }
+ // other exceptions are forwarded to caller...
+ }
+}
+
+void Connection::tryToReconnect() throw (NoMoreControllerException,
+DriverException, UnexpectedException)
+{
+ wstring fctName(L"Connection::tryToReconnect");
//Wait until other methods/Commands are done
LockScope ls(&connectionCS);
+ if (isWarnEnabled())
+ logWarn(fctName, L"Connection to controller lost - trying to reconnect");
+
// close everything
- close();
+ if (isDebugEnabled())
+ logDebug(fctName, L"Closing socket of lost connection");
+
+ isClosed = true;
+ closeSocket();
// try to reconnect to the same controller if it has never been suspected of
// failure before
@@ -1056,10 +1131,10 @@
{
try
{
+ if (isDebugEnabled())
+ logDebug(fctName, L"Trying to reconnect to the same controller...");
if (initConnection() && finalizeConnect())
{
- if (isInfoEnabled())
- logInfo(fctName, L"Reconnection to the same controller succeded");
isClosed = false;
}
}
@@ -1068,45 +1143,40 @@
delete driverSocketPtr; driverSocketPtr = NULL;
}
}
- if (isClosed)
+ if (isClosed) //connection failed
{
+ if (isDebugEnabled())
+ logDebug(fctName, L"Controller " +
static_cast<wstring>(connected_controller)
+ + L" is still not responding, suspecting it of failure");
connect_policy_ptr->suspectControllerOfFailure(connected_controller);
- }
- try
- {
- connected_controller = connect_policy_ptr->getController();
- if (initConnection() && finalizeConnect())
+ try
{
- if (isInfoEnabled())
- logInfo(fctName, L"Connection succeded");
- isClosed = false;
+ if (isDebugEnabled())
+ logDebug(fctName, L"Getting a new controller from the list...");
+ connected_controller = connect_policy_ptr->getController();
+ if (initConnection() && finalizeConnect())
+ {
+ if (isInfoEnabled())
+ logInfo(fctName, L"Connection succeded");
+ isClosed = false;
+ }
+ }
+ catch (AuthenticationException ae)
+ {
+ // Should not happen, this probably mean an inconsistency in controller
+ // configuration but safely ignore (see below)
+ wstring msg = L"Warning! Authentication exception received on connection
retry, controller configuration might be inconsistent";
+ if (isWarnEnabled())
+ logWarn(fctName, msg);
+ throw DriverException(msg+ae.description());
}
}
- catch (AuthenticationException ae)
- {
- // Should not happen, this probably mean an inconsistency in controller
- // configuration but safely ignore (see below)
- wstring msg = L"Warning! Authentication exception received on connection
retry, controller configuration might be inconsistent";
- if (isWarnEnabled())
- logWarn(fctName, msg);
- throw DriverException(msg+ae.description());
- }
- catch (ConnectionException ce)
- {
- // Should not happen, this probably mean an inconsistency in controller
- // configuration but safely ignore (see below)
- wstring msg = L"Warning! Connection exception received on connection
retry, controller configuration might be inconsistent";
- if (isWarnEnabled())
- logWarn(fctName, msg);
- throw DriverException(msg+ce.description());
- }
-
// Connection succeeded, restore the previous connection state on the
// controller
try
{
if (isInfoEnabled())
- logInfo(fctName, L"Restoring connection state on controller "
+ logInfo(fctName, L"Restoring connection state on the new controller "
+ static_cast<wstring>(connected_controller));
sendCommand(*driverSocketPtr, RestoreConnectionState);
*driverSocketPtr<<writeExecutedInTransaction;
@@ -1116,10 +1186,12 @@
*driverSocketPtr<<persistent_connection;
if (persistent_connection)
*driverSocketPtr<<persistent_connection_id;
+ if (isInfoEnabled())
+ logInfo(fctName, L"Transparent reconnection succeeded");
}
catch (SocketIOException sioe)
{
- throw (DriverException(L"Failed to reconnect to controller"
+ throw (ConnectionException(L"Error in reconnection attempt: "
+ sioe.description()));
}
}
Index: carob/src/ControllerConnectPolicy.cpp
diff -u carob/src/ControllerConnectPolicy.cpp:1.10
carob/src/ControllerConnectPolicy.cpp:1.11
--- carob/src/ControllerConnectPolicy.cpp:1.10 Tue Feb 21 17:08:06 2006
+++ carob/src/ControllerConnectPolicy.cpp Fri Feb 24 12:56:41 2006
@@ -152,6 +152,9 @@
bool AbstractControllerConnectPolicy::isSuspectedOfFailure(
const ControllerInfo& controllerInfo)
{
+ // This is a good place to do the ping on suspected controllers, we are
+ // called by most of the functions in this class
+ updateSuspectList();
// Just compare controller info with each item in the whole list
for (SuspectList::const_iterator iter = suspected_controllers.begin();
iter != suspected_controllers.end(); iter++)
@@ -181,6 +184,8 @@
controller_failure_number++;
SuspectController newSuspect;
newSuspect.controllerInfo = controllerInfo;
+ if (isDebugEnabled())
+ logDebug(fctName, L"Creating ping socket to suspect controller...");
// creates and prepares a new socket for pinging the controller
newSuspect.pingSocketPtr = new JavaSocket();
newSuspect.pingSocketPtr->create(false); //create non blocking
Index: carob/test/10-Connection/TestConnect.cpp
diff -u carob/test/10-Connection/TestConnect.cpp:1.4
carob/test/10-Connection/TestConnect.cpp:1.5
--- carob/test/10-Connection/TestConnect.cpp:1.4 Tue Feb 14 18:35:48 2006
+++ carob/test/10-Connection/TestConnect.cpp Fri Feb 24 12:56:41 2006
@@ -115,11 +115,11 @@
// We should receive an exception instead of coming here
CPPUNIT_ASSERT(false);
}
- catch (ConnectionException ce)
+ catch (AuthenticationException ae)
{
if (isErrorEnabled())
logError(fctName, L"Connection failed (this is ok). Exception: "
- + ce.description());
+ + ae.description());
CPPUNIT_ASSERT(true);
}
}
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits