Date: Friday, March 10, 2006 @ 13:37:00
  Author: zsolt
    Path: /cvsroot/carob/libmysequoia

   Added: include/HostTokenizer.hpp (1.1) src/HostTokenizer.cpp (1.1)
Modified: src/CarobMySQL.cpp (1.63 -> 1.64) src/Makefile.am (1.9 -> 1.10)

- implemented HostTokenizer
- removed default port 3306
- integrated HostTokenizer


---------------------------+
 include/HostTokenizer.hpp |   75 ++++++++++++++++++++
 src/CarobMySQL.cpp        |   60 +++++++---------
 src/HostTokenizer.cpp     |  158 ++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am           |    3 
 4 files changed, 262 insertions(+), 34 deletions(-)


Index: libmysequoia/include/HostTokenizer.hpp
diff -u /dev/null libmysequoia/include/HostTokenizer.hpp:1.1
--- /dev/null   Fri Mar 10 13:37:00 2006
+++ libmysequoia/include/HostTokenizer.hpp      Fri Mar 10 13:37:00 2006
@@ -0,0 +1,75 @@
+/*
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005-2006 Continuent, Inc.
+ * Contact: [EMAIL PROTECTED]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Initial developer(s): Zsolt Simon, Csaba Simon
+ * Contributor(s): 
+ */
+
+#ifndef _HOSTTOKENIZER_HPP
+#define _HOSTTOKENIZER_HPP
+
+#include <string>
+#include <vector>
+
+//Carob includes
+#include <ConnectionParameters.hpp>
+
+typedef struct {
+  std::string host;
+  unsigned int port;
+} HOSTPORT;
+
+class HostTokenizerException
+{
+public:
+  /**
+   * Constructor.
+   * @param s The error message.
+   */
+  HostTokenizerException(std::string s) : message(s) {};
+
+  /**
+   * Return the error message.
+   * @return a string containing the error message
+   */
+  const std::string&  description() const { return message; }
+
+private:
+  std::string message;
+};
+
+class HostTokenizer
+{
+public:
+  typedef std::vector<HOSTPORT>::const_iterator const_iterator;
+
+       HostTokenizer(const char *str, const char *defaultpolicy = 0);
+       ~HostTokenizer() {}
+
+  const_iterator begin() { return hosts.begin(); }
+  const_iterator end() { return hosts.end(); }
+
+  CarobNS::ConnectPolicy getPolicy() { return policy; }
+private:
+  std::vector<HOSTPORT> hosts;
+  CarobNS::ConnectPolicy policy;
+  
+  bool validChar(const char *p, const char *first, int state);
+  CarobNS::ConnectPolicy HostTokenizer::findPolicy(const char *pol, int len = 
0);
+};
+
+#endif /*_HOSTTOKENIZER_HPP*/
Index: libmysequoia/src/CarobMySQL.cpp
diff -u libmysequoia/src/CarobMySQL.cpp:1.63 
libmysequoia/src/CarobMySQL.cpp:1.64
--- libmysequoia/src/CarobMySQL.cpp:1.63        Wed Mar  8 08:25:23 2006
+++ libmysequoia/src/CarobMySQL.cpp     Fri Mar 10 13:37:00 2006
@@ -23,6 +23,7 @@
 #include <CarobStmt.hpp>
 #include <IniParser.hpp>
 #include <Utils.hpp>
+#include <HostTokenizer.hpp>
 
 /* MySQL include */
 #include <errmsg.h>
@@ -107,8 +108,6 @@
 {
   LOG4CXX_DEBUG(logger, "Entering connect: host=" << host << " user=" << user 
<< " passwd=" << passwd << " db=" << db << " port=" << port);
   
-  bool defaultport = false;
-  
   if (mysqlPtr->status != MYSQL_STATUS_READY)
   {
     set_error(CR_COMMANDS_OUT_OF_SYNC, SQLT_UNKNOWN);
@@ -163,15 +162,6 @@
       port = 25322;
   }
   
-  //check if the port contains the hardcoded mysql port (3306)
-  //if so, then first try to connect to the default sequoia port (25322)
-  //and if is unsuccessful, then to the 3306 port.
-  if (port == 3306)
-  {
-    port = 25322;
-    defaultport = true;
-  }
-  
   /* set the default character set if not set */
   if (!mysqlPtr->options.charset_name || !*mysqlPtr->options.charset_name)
   {
@@ -197,28 +187,23 @@
   
   try 
   {
-    ConnectionParameters connectionParameters(to_wstring(host), port, 
-      to_wstring(db), to_wstring(user), to_wstring(passwd), DEBUG_LEVEL_OFF, 
DEFAULT_POLICY, DEFAULT_RETRY_INTERVAL, true);
+    HostTokenizer ht(host);
+    HostTokenizer::const_iterator hti = ht.begin();
     
-    Connection *newConnectionPtr;
+    LOG4CXX_DEBUG(logger, "Connect (first host): host=" << hti->host << " 
port=" << hti->port);
+    port = hti->port;
+    ConnectionParameters connectionParameters(to_wstring(hti->host), 
hti->port, 
+      to_wstring(db), to_wstring(user), to_wstring(passwd), DEBUG_LEVEL_OFF, 
ht.getPolicy(), DEFAULT_RETRY_INTERVAL, true);
+    hti++;
     
-    try {
-      newConnectionPtr = new Connection(connectionParameters);
-    }
-    catch (CarobException &e)
+    for (; hti != ht.end(); hti++)
     {
-      //if the default port was given and the connection to port 25322
-      //failed we try the 3306 port
-      if (defaultport && (port == 25322))
-      {
-        ConnectionParameters connectionParameters2(to_wstring(host), 3306,
-          to_wstring(db), to_wstring(user), to_wstring(passwd), 
DEBUG_LEVEL_OFF, DEFAULT_POLICY, DEFAULT_RETRY_INTERVAL, true);
-        newConnectionPtr = new Connection(connectionParameters2);
-      }
-      else
-        throw;
+      connectionParameters.addController(to_wstring(hti->host), hti->port);
+      LOG4CXX_DEBUG(logger, "Connect (adding host): host=" << hti->host << " 
port=" << hti->port);
     }
     
+    Connection *newConnectionPtr = new Connection(connectionParameters);
+    
     if (newConnectionPtr)
     {
       //TODO handle not enough memory
@@ -247,6 +232,13 @@
     LOG4CXX_DEBUG(logger, "Leaving connect.");
     return false;
   }
+  catch (HostTokenizerException &e)
+  {
+    set_error(0, e.description().c_str(), error_sqlstate[SQLT_UNKNOWN]);
+    //TODO error handling
+    LOG4CXX_DEBUG(logger, "Leaving connect.");
+    return false;
+  }
 }
 
 bool
@@ -905,11 +897,13 @@
           break;
         case MYSQL_TYPE_TIMESTAMP:
         case MYSQL_TYPE_DATETIME:
-          SQLTimeStamp ts = drsPtr->getTimeStamp(i+1);
-          getFromDateTime(&b,fPtr,&ts);
-          result += buffer;
-          field_len = *b.length;
-          break;
+          {
+            SQLTimeStamp ts = drsPtr->getTimeStamp(i+1);
+            getFromDateTime(&b,fPtr,&ts);
+            result += buffer;
+            field_len = *b.length;
+            break;
+          }
         default:
           if (fPtr->flags & BINARY_FLAG)
           {
Index: libmysequoia/src/HostTokenizer.cpp
diff -u /dev/null libmysequoia/src/HostTokenizer.cpp:1.1
--- /dev/null   Fri Mar 10 13:37:00 2006
+++ libmysequoia/src/HostTokenizer.cpp  Fri Mar 10 13:37:00 2006
@@ -0,0 +1,158 @@
+/*
+ * Sequoia: Database clustering technology.
+ * Copyright (C) 2005-2006 Continuent, Inc.
+ * Contact: [EMAIL PROTECTED]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Initial developer(s): Zsolt Simon, Csaba Simon
+ * Contributor(s): 
+ */
+
+#include <HostTokenizer.hpp>
+
+#include <ctype.h>
+
+using namespace std;
+using namespace CarobNS;
+
+const char *policy_list[] = {"roundrobin", 0};
+const int MAXDIGITLEN = 5;
+const int MAXBUFFERSIZE = 1024;
+
+HostTokenizer::HostTokenizer(const char *str, const char *defaultpolicy)
+{
+  /* parse a string of format "[host:port] [host2:port2] [policy=xy]" */
+  const char *pl = str, *pf;
+  bool space;
+  HOSTPORT last;
+  //state showing the internal state of the parsing
+  //0 - host or policy expecting
+  //1 - :, host or policy expecting
+  //2 - port expecting
+  //3 - = expecting
+  //4 - selected policy expecting
+  int state = 0;
+  
+  if (defaultpolicy)
+    policy = findPolicy(defaultpolicy);
+  else
+    policy = ROUND_ROBIN;
+  
+  if (pl)
+  {
+    while (*pl)
+    {
+      pf = pl;
+      //skip white spaces from the begining
+      while (*pf && isspace(*pf)) ++pf;
+      space = pf != pl || pf == str;
+      pl = pf;
+      while (*pl && validChar(pl, pf, state)) ++pl;
+      
+      //if we found a token
+      if (pf != pl && ((!state && space) || state))
+      {
+        int len = pl - pf;
+        switch (state)
+        {
+          case 0:
+          case 1:
+            if (state == 1 && *pf == ':')
+              state++;
+            else
+            {
+              if (state == 1)
+              {
+                //we don't have a port so we add the default one
+                last.port = 25322;
+                hosts.push_back(last);
+              }
+
+              if (!strncasecmp(pf,"policy",len))
+                state = 3;
+              else
+              {
+                last.host = string(pf,len);
+                state = 1;
+              }
+            }
+            break;
+        case 2:
+          last.port = 0;
+          while (pf < pl)
+            last.port = last.port*10 + (*pf++ - '0');
+          hosts.push_back(last);
+          state = 0;
+          break;
+        case 3:
+          state++;
+          break;
+        case 4:
+          policy = findPolicy(pf, len);
+          state = 0;
+          break;
+        }
+      }
+      else
+      if (*pf)
+      {
+        char buffer[MAXBUFFERSIZE];
+        snprintf(buffer, sizeof(buffer), "Invalid or unexpected character 
occured '%c' at position: %d", *pf, pf - str);
+        throw HostTokenizerException(buffer);
+      }
+    }
+
+    //if we are in state == 1, it means, there was given a host without port, 
so add it to the list
+    if (state == 1)
+    {
+      last.port = 25322;
+      hosts.push_back(last);
+    }
+  }
+}
+
+bool HostTokenizer::validChar(const char *p, const char *first, int state)
+{
+  switch (state)
+  {
+    case 1:
+      if (*first == ':')
+        return first == p;
+    case 0:
+      return isalnum(*p) || ((first != p) && ((*p == '.') || (*p == '-')));
+    case 2:
+      return isdigit(*p) && (p - first <= MAXDIGITLEN);
+    case 3:
+      if (*first == '=')
+        return first == p;
+    case 4:
+      return isalpha(*p) || (*p == '-');
+  }
+  
+  return false;
+}
+
+ConnectPolicy HostTokenizer::findPolicy(const char *pol, int len)
+{
+  if (!len)
+    len = strlen(pol);
+    
+  const char **p;
+  
+  for (p = policy_list; *p && (strncasecmp(pol,*p,len) != 0); p++) ; 
+  if (*p)
+    return (ConnectPolicy) (p-policy_list);
+  else
+    throw HostTokenizerException("Invalid connect policy: " + string(pol,len));
+}
Index: libmysequoia/src/Makefile.am
diff -u libmysequoia/src/Makefile.am:1.9 libmysequoia/src/Makefile.am:1.10
--- libmysequoia/src/Makefile.am:1.9    Thu Mar  2 17:23:24 2006
+++ libmysequoia/src/Makefile.am        Fri Mar 10 13:37:00 2006
@@ -28,7 +28,8 @@
                            MySQLAPI.cpp \
                            Utils.cpp \
                            IniParser.cpp \
-                           Converter.cpp
+                           Converter.cpp \
+                           HostTokenizer.cpp
 
 libmysequoia_la_CXXFLAGS = @MYSQL_CFLAGS@ @GCOV_CFLAGS@
 libmysequoia_la_LDFLAGS  = -version-info 0:0:0 @GCOV_LDADD@ @LOG4CXX_LDADD@

_______________________________________________
Carob-commits mailing list
[email protected]
https://forge.continuent.org/mailman/listinfo/carob-commits

Reply via email to