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

Reply via email to