memcache/connection.c
changeset 46 8a832c0e01ee
parent 44 03a7e064f833
child 48 1c67f512779b
--- a/memcache/connection.c	Thu Aug 28 01:42:28 2008 +0300
+++ b/memcache/connection.c	Thu Aug 28 03:12:11 2008 +0300
@@ -19,9 +19,10 @@
 static void _memcache_conn_ev_read (evutil_socket_t fd, short event, void *arg);
 
 static void memcache_conn_error (struct memcache_conn *conn);
-static void memcache_conn_req_error (struct memcache_conn *conn);
 static void memcache_conn_req_done (struct memcache_conn *conn);
 
+void memcache_conn_close (struct memcache_conn *conn);
+
 struct memcache_conn *memcache_conn_open (struct memcache_server *server) {
     struct memcache_conn *conn = NULL;
 
@@ -83,31 +84,30 @@
     assert(conn->fd > 0 && conn->is_connected);
     assert(conn->req == NULL);
 
-    // store the req
-    conn->req = req;
-
     // write the request header into our bufferevent's output buffer
     if (memcache_cmd_format_header(bufferevent_get_output(conn->bev), req->cmd_type, &req->key, &req->obj)) {
-        // just fail the request
-        memcache_conn_req_error(conn);
-
         ERROR("failed to init the cmd");
     }
     
+    // store the req
+    conn->req = req;
+    
     // tell our bufferevent to send it
-    if (bufferevent_enable(conn->bev, EV_WRITE)) {
-        // fail the entire connection
-        memcache_conn_error(conn);
-
+    if (bufferevent_enable(conn->bev, EV_WRITE))
         PERROR("bufferevent_enable");
-    }
     
     // tell the req that it is underway
     memcache_req_send(req);
+    
+    // success
+    return;
 
 error:
+    if (conn->req)
+        memcache_conn_error(conn);
 
-    return;
+    else
+        memcache_req_error(req);
 }
 
 /*
@@ -122,6 +122,20 @@
 }
 
 /*
+ * Write out the final \r\n to terminate the request data
+ */
+void memcache_conn_finish_req_data (struct memcache_conn *conn) {
+    if (bufferevent_write(conn->bev, "\r\n", 2))
+        PERROR("bufferevent_write");
+    
+    // ok
+    return;
+
+error:
+    memcache_conn_error(conn);
+}
+
+/*
  * Start reading a reply from the connection
  */
 void memcache_conn_handle_reply (struct memcache_conn *conn) {
@@ -139,7 +153,7 @@
     return;
 
 error:
-    memcache_conn_req_error(conn);
+    memcache_conn_error(conn);
 }
 
 /*
@@ -210,7 +224,7 @@
     return;
 
 error:
-    memcache_conn_req_error(conn);
+    memcache_conn_error(conn);
 }
 
 /*
@@ -258,7 +272,8 @@
     assert(evbuffer_get_length(bufferevent_get_output(bev)) == 0);
     
     // does this request have some data to be included in the request?
-    if (conn->req->buf.data > 0) {
+    // if the data has already been sent (we handle the final \r\n as well), then skip this.
+    if (conn->req->have_buf && conn->req->buf.offset == 0) {
         // we need to send the request data next
         memcache_conn_send_req_data(conn);
 
@@ -322,7 +337,7 @@
     // free the header data read from the buf
     free(header_data);
 
-    memcache_conn_req_error(conn);
+    memcache_conn_error(conn);
 }
 
 
@@ -365,8 +380,8 @@
             PERROR("event_add");
 
     } else {
-        // done! We can handle the reply now
-        memcache_conn_handle_reply(conn);
+        // done! Send the terminating \r\n next
+        memcache_conn_finish_req_data(conn);
     }
 
     // success
@@ -428,35 +443,30 @@
     memcache_conn_error(conn);
 }
 
+// XXX: need to flush/disable buffers/events on errors
+
 /*
  * The entire connection failed
  */
 static void memcache_conn_error (struct memcache_conn *conn) {
     // fail the request, if we have one
-    if (conn->req)
-        memcache_conn_req_error(conn);
+    if (conn->req) {
+        // error out the req
+        memcache_req_error(conn->req);
+        assert(conn->req->conn == NULL);
+        
+        // we are now available again
+        conn->req = NULL;
+    }
+    
+    // close the connection
+    memcache_conn_close(conn);
 
     // tell the server we failed
     memcache_server_conn_dead(conn->server, conn);
 }
 
 /*
- * Request failed somehow
- */
-static void memcache_conn_req_error (struct memcache_conn *conn) {
-    // ensure that we do currently have a req
-    assert(conn->req);
-    
-    // error out the req
-    memcache_req_error(conn->req);
-    assert(conn->req->conn == NULL);
-    
-    // we are now available again
-    conn->req = NULL;
-   
-}
-
-/*
  * Detach the request
  */
 static void memcache_conn_req_done (struct memcache_conn *conn) {
@@ -469,15 +479,11 @@
     
     // we are now available again
     conn->req = NULL;
+    
+    memcache_server_conn_ready(conn->server, conn);
 }
 
-void memcache_conn_free (struct memcache_conn *conn) {
-    // ensure we don't have a req bound to us
-    assert(conn->req == NULL);
-
-    // ensure that the connection is not considered to be connected anymore
-    assert(!conn->is_connected);
-    
+void memcache_conn_close (struct memcache_conn *conn) {
     // close the fd if needed
     if (conn->fd > 0) {
         if (close(conn->fd))
@@ -492,9 +498,23 @@
     assert(event_pending(&conn->ev_write, EV_WRITE|EV_TIMEOUT, NULL) == 0);
     
     // free the bufferevent
-    if (conn->bev)
+    if (conn->bev) {
         bufferevent_free(conn->bev);
 
+        conn->bev = NULL;
+    }
+
+    // not connected anymore
+    conn->is_connected = 0;
+}
+
+void memcache_conn_free (struct memcache_conn *conn) {
+    // ensure we don't have a req bound to us
+    assert(conn->req == NULL);
+    
+    // ensure that the connection is not considered to be connected anymore
+    assert(!conn->is_connected);
+    
     // free it
     free(conn);
 }