Date: Wednesday, December 20, 2006 @ 17:32:49
Author: gilles
Path: /cvsroot/carob/carob
Modified: include/Connection.hpp (1.77 -> 1.78) include/ControllerPool.hpp
(1.11 -> 1.12) src/Connection.cpp (1.99 -> 1.100)
src/ControllerPool.cpp (1.15 -> 1.16)
Partial fix for CAROB-119 (At (re)connection time, when the VDB is not found on
the first controller, other controllers are not tried):
- introduced VirtualDatabaseUnavailableException
- added Connection#getConnectionToNewController() that handles vdb not found
errors
- renamed initConnectionToNextController() to connectToNextController(). It
handles io exceptions (and now calls finalizeConnect() directly)
Remaining: handle vdb states in controller pool
----------------------------+
include/Connection.hpp | 95 +++++++++++-----
include/ControllerPool.hpp | 6 +
src/Connection.cpp | 254 +++++++++++++++----------------------------
src/ControllerPool.cpp | 6 +
4 files changed, 168 insertions(+), 193 deletions(-)
Index: carob/include/Connection.hpp
diff -u carob/include/Connection.hpp:1.77 carob/include/Connection.hpp:1.78
--- carob/include/Connection.hpp:1.77 Mon Dec 18 17:42:55 2006
+++ carob/include/Connection.hpp Wed Dec 20 17:32:49 2006
@@ -128,6 +128,18 @@
AuthenticationException(std::wstring s) : DriverException(s, L"28000") {}
};
+/**
+ * Exception thrown when a vdb does not exist on a controller
+ */
+class VirtualDatabaseUnavailableException : public DriverException
+{
+ public:
+ /**
+ * Constructs a VirtualDatabaseUnavailableException with the given message
+ * @param s error message of the exception
+ */
+ VirtualDatabaseUnavailableException(std::wstring s) : DriverException(s) {}
+};
/**
* This class implements the communication protocol to the Controller.
@@ -154,9 +166,12 @@
* @throw AuthenticationException if a login error occured, or if an
* IO exception occured during authentication (premature close of
* connection)
+ * @throw VirtualDatabaseUnavailableException if none of the remaining
+ * controllers has the desired vdb
*/
- Connection(ConnectionParameters& prms) throw (DriverException,
- ConnectionException, AuthenticationException, UnexpectedException);
+ Connection(ConnectionParameters& prms) throw (AuthenticationException,
+ NoMoreControllerException, VirtualDatabaseUnavailableException,
+ UnexpectedException);
/**
* Closes the connection and destroys its socket
@@ -362,46 +377,70 @@
* After this call, <code>getWarnings()</code> returns <code>null</code>
* until a new call to getWarnings() on this connection.
*/
- void clearWarnings() throw (DriverException,
UnexpectedException);
+ void clearWarnings() throw (DriverException,
UnexpectedException);
/**
* Utility function to convert the given chain of backendException to a chain
* of SQLWarnings
*
* @param bde exception chain to convert
*/
- static SQLWarning* convertToSQLWarnings(BackendException* bde);
+ static SQLWarning* convertToSQLWarnings(BackendException* bde);
protected:
/**
- * Starts a connection by retrieving a new controller to connect to from the
- * pool and sends all connection/authentication informations to it.
- * Warning: this function only sends the connection infos, but there is no
- * guaranty that we are connected afterwards. [EMAIL PROTECTED]
#finalizeConnect()} will
- * do the job of checking and finishing connection establishment.
- * @return true if the connection initialization succeeds
- * @throw NoMoreControllerException if there is no alive controller left
+ * This function should be used to establish a new connection to another
+ * controller in the list. It monitors "virtualdatabase not available"
+ * failures by calling [EMAIL PROTECTED]
#connectToNextController(SequoiaUrl)} only a
+ * limited number of times (number = number of available controllers).
+ *
+ * @throw AuthenticationException if the authentication has failed
+ * @throw DriverSQLException if the connection cannot be established with the
+ * controller
+ * @throw VirtualDatabaseUnavailableException if none of the remaining
+ * controllers has the desired vdb
+ */
+ void getConnectionToNewController()
+ throw (AuthenticationException,
NoMoreControllerException,
+ VirtualDatabaseUnavailableException,
UnexpectedException);
+
+ /**
+ * Connects to the next controller (next according to the current controller
+ * pool).<br>
+ * Retrieves a new controller by asking the controller pool, creates and
+ * connects a socket to this new controller, and registers the new socket to
+ * the policy. Then, tries to authenticate to the controller. Finally,
creates
+ * the connection with the given parameters.<br>
+ * Upon IOException during connection, this function will mark the new
+ * controller as failing and try the next controller until
+ * NoMoreControllerException (which will be forwarded to caller)<br>
+ * If a VirtualDatabaseUnavailableException is thrown, the controller's vdb
+ * will be considered as down and the exception will be forwarded to caller.
+ *
+ * @throw AuthenticationException if the authentication has failed
* @throw ConnectionException if the requested controller could not be
* reached
- * @throw AuthenticationException if a login error occured, or if an
- * IO exception occured during authentication (premature close of
- * connection)
- */
- void initConnectionToNextController()
- throw (NoMoreControllerException,
ConnectionException,
- AuthenticationException, UnexpectedException);
+ * @throw NoMoreControllerException if all controllers in the list are down
+ * @throw VirtualDatabaseUnavailableException if the given vdb is not
+ * available on the new controller we are trying to connect to
+ */
+ void connectToNextController()
+ throw (AuthenticationException,
+ NoMoreControllerException,
+ VirtualDatabaseUnavailableException,
+ UnexpectedException);
/**
* Reads the controller acknowledgements and misc parameters that finish
- * connection. [EMAIL PROTECTED] #initConnectionToNextController()} must be
called before
- * this.
- * @throw ConnectionException if the virtual database is not available on the
- * controller
- * @throw AuthenticationException if the controller did not acknowledge or in
- * case of i/o exception during finalization (premature close of
- * connection)s
- */
- void finalizeConnect() throw (ConnectionException,
- AuthenticationException, UnexpectedException);
+ * connection. To be called only by [EMAIL PROTECTED]
#initConnectionToNextController()}
+ * @throw AuthenticationException if the controller did not acknowledge
+ * @throw SocketIOException in case of i/o error during finalization
+ * @throw VirtualDatabaseUnavailableException if the virtual database is not
+ * available on the controller
+ */
+ void finalizeConnect() throw (AuthenticationException,
+ SocketIOException,
+ VirtualDatabaseUnavailableException,
+ UnexpectedException);
/**
* Deletes all statements created by this connection and closes the socket
Index: carob/include/ControllerPool.hpp
diff -u carob/include/ControllerPool.hpp:1.11
carob/include/ControllerPool.hpp:1.12
--- carob/include/ControllerPool.hpp:1.11 Mon Dec 18 17:42:55 2006
+++ carob/include/ControllerPool.hpp Wed Dec 20 17:32:49 2006
@@ -87,6 +87,12 @@
UnexpectedException) = 0;
/**
+ * Gets the number of controllers still known to be alive
+ * @return the number of alive controllers
+ */
+ int numberOfAliveControllers();
+
+ /**
* Registers the given socket to the callback so it can kill this socket when
* the controller is detected as failed
*
Index: carob/src/Connection.cpp
diff -u carob/src/Connection.cpp:1.99 carob/src/Connection.cpp:1.100
--- carob/src/Connection.cpp:1.99 Mon Dec 11 19:14:45 2006
+++ carob/src/Connection.cpp Wed Dec 20 17:32:49 2006
@@ -71,7 +71,8 @@
}
Connection::Connection(ConnectionParameters& prms)
- throw (DriverException, ConnectionException, AuthenticationException,
UnexpectedException) :
+ throw (AuthenticationException, NoMoreControllerException,
+ VirtualDatabaseUnavailableException, UnexpectedException) :
driverSocketPtr(NULL),
isClosed(true),
autoCommit(true),
@@ -88,46 +89,18 @@
wstring fctName(L"Connection::Connection");
persistent_connection = parameters.getPersistentConnection();
retrieve_sql_warnings = parameters.getRetrieveSQLWarnings();
- for (int connectRetry = 0; connectRetry<CONNECT_RETRIES; connectRetry++)
+ try
{
- try
- {
- // Do the authentication stuff
- initConnectionToNextController();
- // receive ack and other params
- finalizeConnect();
- isClosed = false;
- return;
- }
- // 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
- controller_pool.forceControllerDown(connected_controller);
- }
- catch (ConnectionException& ce)
- {
- //Do some clean up
- delete driverSocketPtr; driverSocketPtr = NULL;
- }
- catch (NoMoreControllerException& nmce)
- {
- // Clean all: we are in constructor, destructor won't be called !
- delete driverSocketPtr; driverSocketPtr = NULL;
- parameters.releaseControllerPool();
- throw (ConnectionException(nmce.description(), L"08001", &nmce));
- }
- // Other exceptions must be reported to the user
- catch (...)
- {
- // Clean all: we are in constructor, destructor won't be called !
- delete driverSocketPtr; driverSocketPtr = NULL;
- parameters.releaseControllerPool();
- throw;
- }
+ getConnectionToNewController();
+ return;
+ }
+ // exceptions must be reported to the user
+ catch (...)
+ {
+ // Clean all: we are in constructor, destructor won't be called !
+ delete driverSocketPtr; driverSocketPtr = NULL;
+ parameters.releaseControllerPool();
+ throw;
}
}
@@ -151,15 +124,38 @@
socket<<static_cast<int32_t>(command);
}
-void Connection::initConnectionToNextController()
- throw (NoMoreControllerException, ConnectionException,
- AuthenticationException, UnexpectedException)
+void Connection::getConnectionToNewController() throw (AuthenticationException,
+ NoMoreControllerException, VirtualDatabaseUnavailableException,
UnexpectedException)
+{
+ // This will count the number of controllers left to connect to upon
+ // VDB not available exceptions
+ // No need to synchronize with getController(): at worth, we will not try
+ // one controller that just reappeared, or we will try two time the same
+ // controller. This is harmless, we just want to prevent endless retry loops
+ int numberOfCtrlsLeft = controller_pool.numberOfAliveControllers();
+ while (numberOfCtrlsLeft > 0)
+ {
+ try
+ {
+ connectToNextController();
+ isClosed = false;
+ return;
+ }
+ catch (VirtualDatabaseUnavailableException vdbue)
+ {
+ numberOfCtrlsLeft--;
+ }
+ }
+ // at this point, we have tried all controllers
+ throw VirtualDatabaseUnavailableException(L"Virtual database "
+ + parameters.getDatabaseName() + L" not found on any of the
controllers");
+}
+
+void Connection::connectToNextController()
+ throw (AuthenticationException, NoMoreControllerException,
+ VirtualDatabaseUnavailableException, UnexpectedException)
{
wstring fctName(L"Connection::initConnectionToNextController");
- bool protocolVersionSend = false,
- dbNameSend = false,
- userNameSend = false,
- userPassSend = false;
try
{
// This must lock the pool synchro to avoid controller list operations
@@ -176,15 +172,12 @@
}
// 2. sent the Protocol version information
*driverSocketPtr<<ProtocolVersion;
- protocolVersionSend = true;
// 3. send the database name
*driverSocketPtr<<parameters.getDatabaseName();
- dbNameSend = true;
// 4. send user/pass
*driverSocketPtr<<parameters.getUserName();
- userNameSend = true;
*driverSocketPtr<<parameters.getUserPass();
- userPassSend = true;
+ finalizeConnect();
}
catch (ConnectionException connExcpt)
{
@@ -195,127 +188,61 @@
logError(fctName, msg);
//suspect failing controller
controller_pool.forceControllerDown(connected_controller);
- throw ConnectionException(msg);
+ // Recurse until no more controller
+ connectToNextController();
}
catch (SocketIOException sockIOExcpt)
{
wstring msg = L"Could not authentify to " +
static_cast<wstring>(connected_controller);
- if (!protocolVersionSend)
- {
- msg+=L". Error while sending protocol version ("
- +sockIOExcpt.description()+L")";
- if (isErrorEnabled())
- {
- logError(fctName, msg);
- }
- throw AuthenticationException(msg);
- }
- else if (!dbNameSend)
- {
- msg+=L". Error while sending database name ("
- +sockIOExcpt.description()+L")";
- if (isErrorEnabled())
- {
- logError(fctName, msg);
- }
- throw AuthenticationException(msg);
- }
- else if (!userNameSend)
- {
- msg+=L". Error while sending user name ("
- +sockIOExcpt.description()+L")";
- if (isErrorEnabled())
- {
- logError(fctName, msg);
- }
- throw AuthenticationException(msg);
- }
- else if (!userPassSend)
- {
- msg+=L". Error while sending user password ("
- +sockIOExcpt.description()+L")";
- if (isErrorEnabled())
- {
- logError(fctName, msg);
- }
- throw AuthenticationException(msg);
- }
- else
- {
- msg+=L". Unknown error:"
- +sockIOExcpt.description();
- if (isErrorEnabled())
- {
- logError(fctName, msg);
- }
- throw AuthenticationException(msg);
- }
+ if (isErrorEnabled())
+ logError(fctName, msg);
+ //suspect failing controller
+ controller_pool.forceControllerDown(connected_controller);
+ // Recurse until no more controller
+ connectToNextController();
+ }
+ catch (VirtualDatabaseUnavailableException vdbue)
+ {
+//TODO:
+// controller_pool.setVdbDownOnController(newController);
+ throw;
}
}
-void Connection::finalizeConnect() throw (ConnectionException,
AuthenticationException,
- UnexpectedException)
+void Connection::finalizeConnect() throw (AuthenticationException,
+ SocketIOException, VirtualDatabaseUnavailableException,
UnexpectedException)
{
wstring fctName(L"Connection::finalizeConnect");
bool vdbFound = false,
- vdbFoundRead = false,
- authenticated = false,
- authenticatedRead = false,
- lineSeparatorSent = false,
- persistentConnectionSent = false,
- persistentConnectionRead = false;
- try
- {
- *driverSocketPtr >> vdbFound;
- vdbFoundRead = true;
- if (!vdbFound)
- {
- wstring vdbReason;
- *driverSocketPtr >> vdbReason;
- throw AuthenticationException(L"Connection failed: "+vdbReason);
- }
- *driverSocketPtr >> authenticated;
- authenticatedRead = true;
- if (!authenticated)
- {
- wstring authReason;
- *driverSocketPtr >> authReason;
- throw AuthenticationException(L"Authentication failed: "+authReason);
- }
- // So the controller can correctly parse our requests
- *driverSocketPtr << LINE_SEPARATOR;
- lineSeparatorSent = true;
- *driverSocketPtr << persistent_connection;
- persistentConnectionSent = true;
- if (persistent_connection)
- {
- bool success = false;
- *driverSocketPtr >> success;
- if (success)
- *driverSocketPtr >> persistent_connection_id;
- else
- throw AuthenticationException(fctName +
- L" No more connection available in the cluster");
- }
- persistentConnectionRead = true;
- *driverSocketPtr << retrieve_sql_warnings;
- }
- catch (SocketIOException sockIOExcpt)
- {
- wstring msg(fctName + L" Authentication failed. Error while ");
- if (!authenticatedRead)
- msg += L"reading controller authenticated ack";
- else if (!lineSeparatorSent)
- msg += L"sending line separator";
- else if (!persistentConnectionSent)
- msg += L"sending whether to use persistent connections";
- else if (!persistentConnectionRead)
- msg += L"reading persistent connection id";
+ authenticated = false;
+ *driverSocketPtr >> vdbFound;
+ if (!vdbFound)
+ {
+ wstring vdbReason;
+ *driverSocketPtr >> vdbReason;
+ throw VirtualDatabaseUnavailableException(L"Connection failed:
"+vdbReason);
+ }
+ *driverSocketPtr >> authenticated;
+ if (!authenticated)
+ {
+ wstring authReason;
+ *driverSocketPtr >> authReason;
+ throw AuthenticationException(L"Authentication failed: "+authReason);
+ }
+ // So the controller can correctly parse our requests
+ *driverSocketPtr << LINE_SEPARATOR;
+ *driverSocketPtr << persistent_connection;
+ if (persistent_connection)
+ {
+ bool success = false;
+ *driverSocketPtr >> success;
+ if (success)
+ *driverSocketPtr >> persistent_connection_id;
else
- msg += L"sending whether to retrieve SQL warnings";
- throw AuthenticationException(msg
- + L"(" + sockIOExcpt.description() + L")");
+ throw AuthenticationException(fctName +
+ L" No more persistent connections available for given virtual
database");
}
+ *driverSocketPtr << retrieve_sql_warnings;
}
void Connection::deleteStatement(Statement* stPtr) throw (DriverException,
UnexpectedException)
@@ -1235,7 +1162,7 @@
}
void Connection::tryToReconnect() throw (NoMoreControllerException,
-DriverException, UnexpectedException)
+ DriverException, UnexpectedException)
{
wstring fctName(L"Connection::tryToReconnect");
//Wait until other methods/Commands are done
@@ -1264,10 +1191,7 @@
{
if (isDebugEnabled())
logDebug(fctName, L"Getting a new controller from the list...");
- initConnectionToNextController();
- finalizeConnect();
- if (isInfoEnabled())
- logInfo(fctName, L"Connection succeded");
+ getConnectionToNewController();
isClosed = false;
}
catch (AuthenticationException ae)
Index: carob/src/ControllerPool.cpp
diff -u carob/src/ControllerPool.cpp:1.15 carob/src/ControllerPool.cpp:1.16
--- carob/src/ControllerPool.cpp:1.15 Mon Dec 11 19:14:45 2006
+++ carob/src/ControllerPool.cpp Wed Dec 20 17:32:49 2006
@@ -85,6 +85,12 @@
alive_controllers.clear();
}
+int AbstractControllerPool::numberOfAliveControllers()
+{
+ LockScope ls(&pool_CS);
+ return alive_controllers.size();
+}
+
void AbstractControllerPool::registerSocket(const ControllerInfo& controller,
JavaSocket* socket)
{
_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits