Fix for bad name servers.
authorBrian Aker <brian@gaz>
Wed, 21 Apr 2010 03:14:19 +0000 (20:14 -0700)
committerBrian Aker <brian@gaz>
Wed, 21 Apr 2010 03:14:19 +0000 (20:14 -0700)
libmemcached/common.h
libmemcached/connect.c
libmemcached/constants.h
libmemcached/do.c
libmemcached/io.c
libmemcached/memcached.c
libmemcached/memcached.h
libmemcached/quit.c
tests/mem_functions.c

index f8f236ed88c9d6a05ebec13e94e406d393deb054..bfbc9220950569b45fddc320d22cb4b503b3b402 100644 (file)
@@ -123,6 +123,8 @@ memcached_return_t run_distribution(memcached_st *ptr);
 #define memcached_set_initialized(__object, __value) ((__object)->options.is_initialized(= (__value))
 #define memcached_set_allocated(__object, __value) ((__object)->options.is_allocated(= (__value))
 
+LIBMEMCACHED_LOCAL
+void set_last_disconnected_host(memcached_server_write_instance_st ptr);
 
 LIBMEMCACHED_LOCAL
 memcached_return_t memcached_key_test(const char * const *keys,
index 99238d8ddba9efa216169662375bc8d311009659..cb093d12a1ce5af1fecc0b5050e9d32877a830bc 100644 (file)
@@ -2,13 +2,14 @@
 #include <netdb.h>
 #include <poll.h>
 #include <sys/time.h>
+#include <time.h>
 
 static memcached_return_t set_hostinfo(memcached_server_st *server)
 {
   struct addrinfo *ai;
   struct addrinfo hints;
-  int e;
   char str_port[NI_MAXSERV];
+  uint32_t counter= 5;
 
   snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port);
 
@@ -26,12 +27,31 @@ static memcached_return_t set_hostinfo(memcached_server_st *server)
     hints.ai_protocol= IPPROTO_TCP;
   }
 
-  e= getaddrinfo(server->hostname, str_port, &hints, &ai);
-  if (e != 0)
+  while (--counter)
   {
-    WATCHPOINT_STRING(server->hostname);
-    WATCHPOINT_STRING(gai_strerror(e));
-    return MEMCACHED_HOST_LOOKUP_FAILURE;
+    int e= getaddrinfo(server->hostname, str_port, &hints, &ai);
+
+    if (e == 0)
+    {
+      break;
+    }
+    else if (e == EAI_AGAIN)
+    {
+      struct timespec dream, rem;
+
+      dream.tv_nsec= 1000;
+      dream.tv_sec= 0;
+
+      nanosleep(&dream, &rem);
+
+      continue;
+    }
+    else
+    {
+      WATCHPOINT_STRING(server->hostname);
+      WATCHPOINT_STRING(gai_strerror(e));
+      return MEMCACHED_HOST_LOOKUP_FAILURE;
+    }
   }
 
   if (server->address_info)
@@ -269,8 +289,7 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
       (void)set_socket_options(ptr);
 
       /* connect to server */
-      while (ptr->fd != -1 &&
-             connect(ptr->fd, use->ai_addr, use->ai_addrlen) < 0)
+      if ((connect(ptr->fd, use->ai_addr, use->ai_addrlen) == -1))
       {
         ptr->cached_errno= errno;
         if (errno == EINPROGRESS || /* nonblocking mode - first return, */
@@ -279,20 +298,48 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
           struct pollfd fds[1];
           fds[0].fd = ptr->fd;
           fds[0].events = POLLOUT;
-          int error= poll(fds, 1, ptr->root->connect_timeout);
 
-          if (error != 1 || fds[0].revents & POLLERR)
+          int timeout= ptr->root->connect_timeout;
+          if (ptr->root->flags.no_block == false)
+            timeout= -1;
+
+          size_t loop_max= 5;
+          while (--loop_max)
           {
-            if (fds[0].revents & POLLERR)
+            int error= poll(fds, 1, timeout);
+
+            switch (error)
             {
-              int err;
-              socklen_t len = sizeof (err);
-              (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-              ptr->cached_errno= (err == 0) ? errno : err;
+            case 1:
+              loop_max= 1;
+              break;
+            case 0:
+              continue;
+              // A real error occurred and we need to completely bail
+            default:
+              WATCHPOINT_ERRNO(errno);
+              switch (errno)
+              {
+#ifdef TARGET_OS_LINUX
+              case ERESTART:
+#endif
+              case EINTR:
+                continue;
+              default:
+                if (fds[0].revents & POLLERR)
+                {
+                  int err;
+                  socklen_t len= sizeof (err);
+                  (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
+                  ptr->cached_errno= (err == 0) ? errno : err;
+                }
+
+                (void)close(ptr->fd);
+                ptr->fd= -1;
+
+                break;
+              }
             }
-
-            (void)close(ptr->fd);
-            ptr->fd= -1;
           }
         }
         else if (errno == EISCONN) /* we are connected :-) */
@@ -332,6 +379,8 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
 
   if (ptr->fd == -1)
   {
+    WATCHPOINT_STRING("Never got a good file descriptor");
+
     /* Failed to connect. schedule next retry */
     if (ptr->root->retry_timeout)
     {
@@ -350,11 +399,16 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
   return MEMCACHED_SUCCESS; /* The last error should be from connect() */
 }
 
-static inline void set_last_disconnected_host(memcached_server_write_instance_st ptr)
+void set_last_disconnected_host(memcached_server_write_instance_st ptr)
 {
   // const_cast
   memcached_st *root= (memcached_st *)ptr->root;
 
+#if 0
+  WATCHPOINT_STRING(ptr->hostname);
+  WATCHPOINT_NUMBER(ptr->port);
+  WATCHPOINT_ERRNO(ptr->cached_errno);
+#endif
   if (root->last_disconnected_server)
     memcached_server_free(root->last_disconnected_server);
   root->last_disconnected_server= memcached_server_clone(NULL, ptr);
index 4a7b0cdb8f6dd655a7b49d6bfe4a423463496853..d6798d0d4562f96de0c0ec672a5949c1cc75e008 100644 (file)
@@ -22,6 +22,7 @@
 #define MEMCACHED_CONTINUUM_SIZE MEMCACHED_POINTS_PER_SERVER*100 /* This would then set max hosts to 100 */
 #define MEMCACHED_STRIDE 4
 #define MEMCACHED_DEFAULT_TIMEOUT 1000
+#define MEMCACHED_DEFAULT_CONNECT_TIMEOUT 4000
 #define MEMCACHED_CONTINUUM_ADDITION 10 /* How many extra slots we should build for in the continuum */
 #define MEMCACHED_PREFIX_KEY_MAX_SIZE 128
 #define MEMCACHED_EXPIRATION_NOT_ADD 0xffffffffU
index 794303a89383f1ace1706bcb980c3978e8e0b292..1a274cd336ef4d4f9baee3718c4e237086c1f944 100644 (file)
@@ -87,6 +87,8 @@ memcached_return_t memcached_vdo(memcached_server_write_instance_st ptr,
   if (sent_length == -1 || (size_t)sent_length != command_length)
   {
     rc= MEMCACHED_WRITE_FAILURE;
+    WATCHPOINT_ERROR(rc);
+    WATCHPOINT_ERRNO(errno);
   }
   else if ((ptr->root->flags.no_reply) == 0)
   {
index 616ad497b9798147229106c4c459788ccb11f913..070af6b19462d9056f7a3181ba4944e26ae7b9cf 100644 (file)
@@ -64,20 +64,25 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
     case 1:
       return MEMCACHED_SUCCESS;
     case 0:
-      return MEMCACHED_TIMEOUT;
-#ifdef TARGET_OS_LINUX
-    case ERESTART:
-#endif
-    case EINTR:
       continue;
     default:
-      ptr->cached_errno= error;
-      memcached_quit_server(ptr, true);
+      WATCHPOINT_ERRNO(errno);
+      {
+        switch (errno)
+        {
+        default:
+          ptr->cached_errno= error;
+          memcached_quit_server(ptr, true);
 
-      return MEMCACHED_FAILURE;
+          return MEMCACHED_FAILURE;
+        }
+      }
     }
   }
 
+  if (loop_max == 0 && error == 0)
+    return MEMCACHED_TIMEOUT;
+
   /* Imposssible for anything other then -1 */
   WATCHPOINT_ASSERT(error == -1);
   ptr->cached_errno= error;
@@ -583,6 +588,7 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr,
     if (sent_length == -1)
     {
       ptr->cached_errno= errno;
+      WATCHPOINT_ERRNO(errno);
       switch (errno)
       {
       case ENOBUFS:
index e6124493830f9fa31b8738512744f5ecbae0c265..d5411e86c0ba3becb6934e9981cbec2e36a859cf 100644 (file)
@@ -69,7 +69,7 @@ static inline bool _memcached_init(memcached_st *self)
   self->io_key_prefetch= 0;
   self->cached_errno= 0;
   self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
-  self->connect_timeout= MEMCACHED_DEFAULT_TIMEOUT;
+  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
   self->retry_timeout= 0;
   self->continuum_count= 0;
 
@@ -151,6 +151,15 @@ void memcached_servers_reset(memcached_st *ptr)
   ptr->server_failure_limit= 0;
 }
 
+void memcached_reset_last_disconnected_server(memcached_st *ptr)
+{
+  if (ptr->last_disconnected_server)
+  {
+    memcached_server_free(ptr->last_disconnected_server);
+    ptr->last_disconnected_server= NULL;
+  }
+}
+
 void memcached_free(memcached_st *ptr)
 {
   /* If we have anything open, lets close it now */
index 69b469dc3ed9a1617511b8e0bad3c8ebc39ec6c7..26f101f2ea81d75f2924237fa12d73b783c8e6ff 100644 (file)
@@ -146,6 +146,9 @@ memcached_st *memcached_create(memcached_st *ptr);
 LIBMEMCACHED_API
 void memcached_free(memcached_st *ptr);
 
+LIBMEMCACHED_API
+void memcached_reset_last_disconnected_server(memcached_st *ptr);
+
 LIBMEMCACHED_API
 memcached_st *memcached_clone(memcached_st *clone, const memcached_st *ptr);
 
index 592373f60a8e5527db83c775e959d4c19961fe95..49af996374b187f49be1cc2808cc6eb4c82c180f 100644 (file)
@@ -67,6 +67,7 @@ void memcached_quit_server(memcached_server_st *ptr, bool io_death)
   if (io_death)
   {
     ptr->server_failure_counter++;
+    set_last_disconnected_host(ptr);
   }
 }
 
index 57b1c7b4aa81e70e2c080ac63e08da17261d2bab..701de4424c8d90c6ba8f2e7faa5a5010d0dc6e53 100644 (file)
@@ -5417,6 +5417,7 @@ static test_return_t test_get_last_disconnect(memcached_st *memc)
   const char *key= "marmotte";
   const char *value= "milka";
 
+  memcached_reset_last_disconnected_server(memc);
   rc= memcached_set(memc, key, strlen(key),
                     value, strlen(value),
                     (time_t)0, (uint32_t)0);
@@ -5444,7 +5445,12 @@ static test_return_t test_get_last_disconnect(memcached_st *memc)
                     (time_t)0, (uint32_t)0);
   test_true(rc != MEMCACHED_SUCCESS);
 
-  disconnected_server = memcached_server_get_last_disconnect(mine);
+  disconnected_server= memcached_server_get_last_disconnect(mine);
+  if (disconnected_server == NULL)
+  {
+    fprintf(stderr, "RC %s\n", memcached_strerror(mine, rc));
+    abort();
+  }
   test_true(disconnected_server != NULL);
   test_true(memcached_server_port(disconnected_server)== 9);
   test_true(strncmp(memcached_server_name(disconnected_server),"localhost",9) == 0);
@@ -5647,9 +5653,9 @@ static test_return_t regression_bug_490486(memcached_st *memc)
   return TEST_SUCCESS;
 }
 
-static void memcached_die(memcached_st* mc, memcached_return error, const char* what, int it)
+static void memcached_die(memcached_st* mc, memcached_return error, const char* what, uint32_t it)
 {
-  fprintf(stderr, "Iteration #%i: ", it);
+  fprintf(stderr, "Iteration #%u: ", it);
 
   if(error == MEMCACHED_ERRNO)
   {
@@ -5661,17 +5667,19 @@ static void memcached_die(memcached_st* mc, memcached_return error, const char*
     fprintf(stderr, "error %d from %s: %s\n", error, what,
             memcached_strerror(mc, error));
   }
-
-  abort();
 }
 
-#define TEST_CONSTANT_CREATION 400
+#define TEST_CONSTANT_CREATION 200
 
 static test_return_t regression_bug_(memcached_st *memc)
 {
-  memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 0);
-  const char *servername= memcached_server_name(instance);
-  in_port_t port= memcached_server_port(instance);
+  const char *remote_server;
+  (void)memc;
+
+  if (! (remote_server= getenv("LIBMEMCACHED_REMOTE_SERVER")))
+  {
+    return TEST_SKIPPED;
+  }
 
   for (uint32_t x= 0; x < TEST_CONSTANT_CREATION; x++) 
   {
@@ -5690,8 +5698,8 @@ static test_return_t regression_bug_(memcached_st *memc)
       memcached_die(mc, rc, "memcached_behavior_set", x);
     }
 
-    rc= memcached_server_add(mc, servername, port);
-    if(rc != MEMCACHED_SUCCESS)
+    rc= memcached_server_add(mc, remote_server, 0);
+    if (rc != MEMCACHED_SUCCESS)
     {
       memcached_die(mc, rc, "memcached_server_add", x);
     }
@@ -5701,42 +5709,53 @@ static test_return_t regression_bug_(memcached_st *memc)
     const char *set_value= "a value";
     const size_t set_value_len= strlen(set_value);
 
-    char *get_value=NULL;
-    size_t get_value_len=0;
-    uint32_t get_value_flags=0;
-    if (x > 0) 
+    if (rc == MEMCACHED_SUCCESS)
     {
-      get_value= memcached_get(mc, set_key, set_key_len, &get_value_len,
-                               &get_value_flags, &rc);
-      if (rc != MEMCACHED_SUCCESS)
+      if (x > 0) 
       {
-        memcached_die(mc, rc, "memcached_get", x);
+        size_t get_value_len;
+        char *get_value;
+        uint32_t get_value_flags;
+
+        get_value= memcached_get(mc, set_key, set_key_len, &get_value_len,
+                                 &get_value_flags, &rc);
+        if (rc != MEMCACHED_SUCCESS)
+        {
+          memcached_die(mc, rc, "memcached_get", x);
+        }
+        else
+        {
+
+          if (x != 0 &&
+              (get_value_len != set_value_len
+               || 0!=strncmp(get_value, set_value, get_value_len)))
+          {
+            fprintf(stderr, "Values don't match?\n");
+            rc= MEMCACHED_FAILURE;
+          }
+          free(get_value);
+        }
       }
 
-      if (x != 0 &&
-          (get_value_len != set_value_len
-           || 0!=strncmp(get_value, set_value, get_value_len)))
+      rc= memcached_set(mc,
+                        set_key, set_key_len,
+                        set_value, set_value_len,
+                        0, /* time */
+                        0  /* flags */
+                       );
+      if (rc != MEMCACHED_SUCCESS)
       {
-        fprintf(stderr, "Values don't match?\n");
+        memcached_die(mc, rc, "memcached_set", x);
       }
-      free(get_value);
-      get_value= NULL;
-      get_value_len= 0;
     }
 
-    rc= memcached_set(mc,
-                      set_key, set_key_len,
-                      set_value, set_value_len,
-                      0, /* time */
-                      0  /* flags */
-                     );
+    memcached_quit(mc);
+    memcached_free(mc);
+
     if (rc != MEMCACHED_SUCCESS)
     {
-      memcached_die(mc, rc, "memcached_set", x);
+      break;
     }
-
-    memcached_quit(mc);
-    memcached_free(mc);
   }
 
   return MEMCACHED_SUCCESS;
@@ -5933,7 +5952,7 @@ test_st replication_tests[]= {
 test_st regression_tests[]= {
   {"lp:434484", 1, (test_callback_fn)regression_bug_434484 },
   {"lp:434843", 1, (test_callback_fn)regression_bug_434843 },
-  {"lp:434843 buffered", 1, (test_callback_fn)regression_bug_434843_buffered },
+  {"lp:434843-buffered", 1, (test_callback_fn)regression_bug_434843_buffered },
   {"lp:421108", 1, (test_callback_fn)regression_bug_421108 },
   {"lp:442914", 1, (test_callback_fn)regression_bug_442914 },
   {"lp:447342", 1, (test_callback_fn)regression_bug_447342 },