Getting everything ready for non-blocking IO.
authorBrian Aker <brian@tangent.org>
Tue, 2 Oct 2007 23:52:14 +0000 (16:52 -0700)
committerBrian Aker <brian@tangent.org>
Tue, 2 Oct 2007 23:52:14 +0000 (16:52 -0700)
Everything in library now goes through memcached_response()
New memcached_behavior_set() was written so that you can
adjust how the library works.

include/memcached.h
lib/Makefile.am
lib/memcached_auto.c
lib/memcached_behavior.c [new file with mode: 0644]
lib/memcached_connect.c
lib/memcached_response.c
lib/memcached_storage.c
lib/memcached_strerror.c
tests/output.res

index 3733b2f10f48df34bdb929e244c9e0ee43e7c3f2..e9a61f28d650bf5279dd85a550f50a4f59b2cbc6 100644 (file)
@@ -57,6 +57,7 @@ typedef enum {
   MEMCACHED_DATA_EXISTS,
   MEMCACHED_DATA_DOES_NOT_EXIST,
   MEMCACHED_NOTSTORED,
+  MEMCACHED_STORED,
   MEMCACHED_NOTFOUND,
   MEMCACHED_MEMORY_ALLOCATION_FAILURE,
   MEMCACHED_PARTIAL_READ,
@@ -68,6 +69,10 @@ typedef enum {
   MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
 } memcached_return;
 
+typedef enum {
+  MEMCACHED_BEHAVIOR_NO_BLOCK,
+} memcached_behavior;
+
 typedef enum {
   MEMCACHED_NOT_ALLOCATED= 0,
   MEMCACHED_ALLOCATED= 1,
@@ -108,6 +113,8 @@ struct memcached_stat_st {
   unsigned int limit_maxbytes;
 };
 
+#define MEM_NO_BLOCK     (1 << 0)
+
 struct memcached_string_st {
   char *string;
   char *end;
@@ -127,6 +134,10 @@ struct memcached_st {
   size_t write_buffer_offset;
   size_t write_between_flush;
   char connected;
+  int my_errno;
+  unsigned int stack_responses;
+  unsigned long long flags;
+  memcached_return warning; /* Future Use */
 };
 
 /* Public API */
@@ -150,6 +161,7 @@ memcached_return memcached_flush(memcached_st *ptr, time_t expiration);
 memcached_return memcached_verbosity(memcached_st *ptr, unsigned int verbosity);
 void memcached_quit(memcached_st *ptr);
 char *memcached_strerror(memcached_st *ptr, memcached_return rc);
+memcached_return memcached_behavior_set(memcached_st *ptr, memcached_behavior flag);
 
 /* All of the functions for adding data to the server */
 memcached_return memcached_set(memcached_st *ptr, char *key, size_t key_length, 
@@ -225,6 +237,7 @@ void memcached_string_free(memcached_st *ptr, memcached_string_st *string);
 #define WATCHPOINT_ERROR(A) printf("WATCHPOINT %s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, A));fflush(stdout);
 #define WATCHPOINT_STRING(A) printf("WATCHPOINT %s:%d %s\n", __FILE__, __LINE__, A);fflush(stdout);
 #define WATCHPOINT_NUMBER(A) printf("WATCHPOINT %s:%d %d\n", __FILE__, __LINE__, A);fflush(stdout);
+#define WATCHPOINT_ERRNO(A) printf("WATCHPOINT %s:%d %s\n", __FILE__, __LINE__, strerror(A));A= 0;fflush(stdout);
 
 
 #ifdef __cplusplus
index 4ba350fb14dc2f15d3247721db7e089266454c94..8ff7b139edf57a41b1f0a7cd8b93df17a1dd9a81 100644 (file)
@@ -27,6 +27,7 @@ noinst_HEADERS = libmemcached_probes.h \
 lib_LTLIBRARIES = libmemcached.la
 libmemcached_la_SOURCES = memcached.c \
                          memcached_auto.c \
+                         memcached_behavior.c \
                          memcached_connect.c \
                          memcached_delete.c \
                          memcached_flush.c \
index e779f279a7966928f5d95e7add9cf73c4d591d6e..0bb91fd0cd0bf78ad04ea8562203479b93d617cf 100644 (file)
@@ -30,8 +30,16 @@ static memcached_return memcached_auto(memcached_st *ptr,
     return MEMCACHED_WRITE_FAILURE;
 
   memset(buffer, 0, MEMCACHED_DEFAULT_COMMAND_SIZE);
-  send_length= read(ptr->hosts[server_key].fd, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE);
 
+  rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
+
+  /* 
+    So why recheck responce? Because the protocol is brain dead :)
+    The number returned might end up equaling one of the string 
+    values. Less chance of a mistake with memcmp() so we will 
+    use it. We still called memcached_response() though since it
+    worked its magic for non-blocking IO.
+  */
   if (!memcmp(buffer, "ERROR\r\n", MEMCACHED_DEFAULT_COMMAND_SIZE))
   {
     *value= 0;
diff --git a/lib/memcached_behavior.c b/lib/memcached_behavior.c
new file mode 100644 (file)
index 0000000..1095168
--- /dev/null
@@ -0,0 +1,13 @@
+#include <memcached.h>
+
+memcached_return memcached_behavior_set(memcached_st *ptr, memcached_behavior flag)
+{
+  switch (flag)
+  {
+  case MEMCACHED_BEHAVIOR_NO_BLOCK:
+    ptr->flags|= MEM_NO_BLOCK;
+    break;
+  }
+
+  return MEMCACHED_SUCCESS;
+}
index 2120db5c7b4e3d3a5f5aa8bde378490bbf6c765f..5b024749b1f58038f24c515361c5d7f49a0e1365 100644 (file)
@@ -31,7 +31,10 @@ memcached_return memcached_connect(memcached_st *ptr)
 
       /* Create the socket */
       if ((ptr->hosts[0].fd= socket(AF_INET, SOCK_STREAM, 0)) < 0)
+      {
+        ptr->my_errno= errno;
         return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
+      }
 
 
       /* bind any port number */
@@ -39,18 +42,32 @@ memcached_return memcached_connect(memcached_st *ptr)
       localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
       localAddr.sin_port = htons(0);
 
-#ifdef NOT_YET
       /* For the moment, not getting a nonblocking mode will note be fatal */
-      flags= fcntl(ptr->hosts[0].fd, F_GETFL, 0);
-      if (flags != -1)
-        (void)fcntl(ptr->hosts[0].fd, F_SETFL, flags | O_NONBLOCK);
-#endif
+      if (ptr->flags & MEM_NO_BLOCK)
+      {
+        flags= fcntl(ptr->hosts[0].fd, F_GETFL, 0);
+        if (flags != -1)
+          (void)fcntl(ptr->hosts[0].fd, F_SETFL, flags | O_NONBLOCK);
+      }
 
       /* connect to server */
+test_connect:
       if (connect(ptr->hosts[0].fd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
+      {
+        switch (errno) {
+          /* We are spinning waiting on connect */
+        case EINPROGRESS:
+        case EINTR:
+          goto test_connect;
+        case EISCONN: /* We were spinning waiting on connect */
+          break;
+        default:
+        ptr->my_errno= errno;
         return MEMCACHED_HOST_LOCKUP_FAILURE;
+      }
 
       ptr->connected++;
+      }
     }
   }
   LIBMEMCACHED_MEMCACHED_CONNECT_END();
index 24ee832f148a593ab9791f049abb1308d2170aad..42a06411175db1e664ac80e5d5bef1cc748c0324 100644 (file)
@@ -6,6 +6,7 @@
 */
 
 #include "common.h"
+#include "memcached_io.h"
 
 memcached_return memcached_response(memcached_st *ptr, 
                                     char *buffer, size_t buffer_length,
@@ -42,10 +43,12 @@ memcached_return memcached_response(memcached_st *ptr,
     return MEMCACHED_SUCCESS;
   case 'S': /* STORED STATS SERVER_ERROR */
     {
-      if (buffer[1] == 'T') /* STORED STATS */
+      if (buffer[2] == 'A') /* STORED STATS */
         return MEMCACHED_SUCCESS;
       else if (buffer[1] == 'E')
         return MEMCACHED_SERVER_ERROR;
+      else if (buffer[1] == 'T')
+        return MEMCACHED_STORED;
       else
         return MEMCACHED_UNKNOWN_READ_FAILURE;
     }
index 0c27c76681fdfc310c39bf99488decaec842becc..1e607c24e48f9692953fe4b62235c33af9faace5 100644 (file)
@@ -32,6 +32,7 @@ static memcached_return memcached_send(memcached_st *ptr,
   if (rc != MEMCACHED_SUCCESS)
     return rc;
 
+  /* Leaveing this assert in since only a library fubar could blow this */
   assert(ptr->write_buffer_offset == 0);
 
   server_key= memcached_generate_hash(key, key_length) % ptr->number_of_hosts;
@@ -51,7 +52,6 @@ static memcached_return memcached_send(memcached_st *ptr,
     rc= MEMCACHED_WRITE_FAILURE;
     goto error;
   }
-  assert(write_length == sent_length);
 
   /* 
     We have to flush after sending the command. Memcached is not smart enough
@@ -65,7 +65,6 @@ static memcached_return memcached_send(memcached_st *ptr,
     rc= MEMCACHED_WRITE_FAILURE;
     goto error;
   }
-  assert(value_length == sent_length);
 
   if ((sent_length= memcached_io_write(ptr, server_key, "\r\n", 2)) == -1)
   {
@@ -73,26 +72,15 @@ static memcached_return memcached_send(memcached_st *ptr,
     goto error;
   }
 
-  assert(2 == sent_length);
-
   if ((sent_length= memcached_io_flush(ptr, server_key)) == -1)
     return MEMCACHED_WRITE_FAILURE;
 
-  //assert(sent_length == write_length + value_length + 2);
-
-  sent_length= recv(ptr->hosts[server_key].fd, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, 0);
+  rc= memcached_response(ptr, buffer, MEMCACHED_DEFAULT_COMMAND_SIZE, server_key);
 
-  if (sent_length && buffer[0] == 'S')  /* STORED */
+  if (rc == MEMCACHED_STORED)
     return MEMCACHED_SUCCESS;
-  else if (write_length && buffer[0] == 'N')  /* NOT_STORED */
-    return MEMCACHED_NOTSTORED;
-  else if (write_length && buffer[0] == 'E')  /* ERROR */
-  {
-    printf("BUFFER :%s:\n", buffer);
-    return MEMCACHED_PROTOCOL_ERROR;
-  }
-  else
-    return MEMCACHED_READ_FAILURE;
+  else 
+    return rc;
 
 error:
   memcached_io_reset(ptr, server_key);
index c917e96e7e3c8dd58c71df96a8c81751761c0238..43c36a488c352a06d2833064b6b5609f5cd354a1 100644 (file)
@@ -34,6 +34,8 @@ char *memcached_strerror(memcached_st *ptr, memcached_return rc)
     return "CONNECTION DATA DOES NOT EXIST";
   case MEMCACHED_NOTSTORED:
     return "NOT STORED";
+  case MEMCACHED_STORED:
+    return "STORED";
   case MEMCACHED_NOTFOUND:
     return "NOT FOUND";
   case MEMCACHED_MEMORY_ALLOCATION_FAILURE:
index 50dd00ba53efe567bd34a79ee48ba367271457c8..974aa22d62c5b067a1fc2576a672e9d60d7f9959 100644 (file)
@@ -13,14 +13,15 @@ Error 11 -> CONNECTION SOCKET CREATE FAILURE
 Error 12 -> CONNECTION DATA EXISTS
 Error 13 -> CONNECTION DATA DOES NOT EXIST
 Error 14 -> NOT STORED
-Error 15 -> NOT FOUND
-Error 16 -> MEMORY ALLOCATION FAILURE
-Error 17 -> PARTIAL READ
-Error 18 -> SOME ERRORS WERE REPORTED
-Error 19 -> NO SERVERS DEFINED
-Error 20 -> SERVER END
-Error 21 -> SERVER DELETE
-Error 22 -> SERVER VALUE
+Error 15 -> STORED
+Error 16 -> NOT FOUND
+Error 17 -> MEMORY ALLOCATION FAILURE
+Error 18 -> PARTIAL READ
+Error 19 -> SOME ERRORS WERE REPORTED
+Error 20 -> NO SERVERS DEFINED
+Error 21 -> SERVER END
+Error 22 -> SERVER DELETE
+Error 23 -> SERVER VALUE
 Found key pid
 Found key uptime
 Found key time