memcache/server.c
changeset 48 1c67f512779b
parent 46 8a832c0e01ee
child 49 10c7dce1a043
equal deleted inserted replaced
47:a5c09677ca6f 48:1c67f512779b
    21     // init lists
    21     // init lists
    22     LIST_INIT(&server->conn_list);
    22     LIST_INIT(&server->conn_list);
    23     TAILQ_INIT(&server->req_queue);
    23     TAILQ_INIT(&server->req_queue);
    24     
    24     
    25     // grow connpool so as to have a connection ready
    25     // grow connpool so as to have a connection ready
    26     if (memcache_server_grow_connpool(server))
    26     memcache_server_grow_connpool(server);
    27         ERROR("error opening initial connection");
       
    28 
    27 
    29     // success
    28     // success
    30     return server;
    29     return server;
    31 
    30 
    32 error:
    31 error:
    33     free(server);
    32     free(server);
    34 
    33 
    35     return NULL;
    34     return NULL;
    36 }
    35 }
    37 
    36 
    38 int memcache_server_grow_connpool (struct memcache_server *server) {
    37 void memcache_server_grow_connpool (struct memcache_server *server) {
    39    struct memcache_conn *conn;
    38     struct memcache_conn *conn;
    40    int count;
    39     int count = 0;
    41 
    40 
    42    // count connections
    41     // count connections
    43    for (count = 0, conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next, count++) ;
    42     LIST_FOREACH(conn, &server->conn_list, connlist_node) {
       
    43         count++;
       
    44     }
    44 
    45 
    45    // room for more?
    46     // room for more?
    46    if (count < server->max_connections) {
    47     if (count < server->max_connections) {
    47         // create a new one
    48         // create a new one
    48         if ((conn = memcache_conn_open(server)) == NULL)
    49         if ((conn = memcache_conn_open(server)) == NULL)
    49             return -1;
    50             ERROR("failed to grow the connpool");
    50         
    51        
    51         // enlist it
    52         // enlist it
    52         LIST_INSERT_HEAD(&server->conn_list, conn, connlist_node);
    53         LIST_INSERT_HEAD(&server->conn_list, conn, connlist_node);
    53 
    54 
    54         // the connection will call memcache_server_coon_ready once it's ready for use...
    55         // the connection will call memcache_server_coon_ready once it's ready for use...
    55    }
    56     }
    56     
    57 
    57    // success
    58     // ok
    58    return 0;
    59     return;
       
    60 
       
    61 error:
       
    62     // XXX: we might be deadlocked now... requests queued, but no connections!
       
    63     if (LIST_EMPTY(&server->conn_list) && !TAILQ_EMPTY(&server->req_queue))
       
    64         FATAL("deadlock; requests queued, but no connections");
       
    65 
       
    66     // XXX: harmless... but need some retry logic
    59 }
    67 }
    60 
    68 
    61 int memcache_server_add_req (struct memcache_server *server, struct memcache_req *req) {
    69 int memcache_server_add_req (struct memcache_server *server, struct memcache_req *req) {
    62     struct memcache_conn *conn;
    70     struct memcache_conn *conn;
    63     
    71     
    64     // look for an idle connection
    72     // look for an idle connection
    65     for (conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next) {
    73     LIST_FOREACH(conn, &server->conn_list, connlist_node) {
    66         if (memcache_conn_is_available(conn)) {
    74         if (memcache_conn_is_available(conn)) {
    67             // we found an idle connection
    75             // we found an idle connection
    68             break;
    76             break;
    69         }
    77         }
    70     }
    78     }
    83         TAILQ_INSERT_TAIL(&server->req_queue, req, reqqueue_node);
    91         TAILQ_INSERT_TAIL(&server->req_queue, req, reqqueue_node);
    84         
    92         
    85         // notify the req
    93         // notify the req
    86         memcache_req_queued(req);
    94         memcache_req_queued(req);
    87 
    95 
       
    96         // grow the connpool, as we apparently don't have enough connections
       
    97         memcache_server_grow_connpool(server);
       
    98 
    88         return 0;
    99         return 0;
    89     }
   100     }
    90 }
   101 }
    91 
   102 
       
   103 /*
       
   104  * We might have available connections, process any queued requests, or try and grow the connpool if non available
       
   105  */
       
   106 void memache_server_dequeue (struct memcache_server *server) {
       
   107     struct memcache_conn *conn;
       
   108     struct memcache_req *req;
       
   109 
       
   110     // if no requests are queued, nothing needs doing
       
   111     if ((req = TAILQ_FIRST(&server->req_queue)) == NULL)
       
   112         return;
       
   113     
       
   114     // look for idle connections to service the request
       
   115     LIST_FOREACH(conn, &server->conn_list, connlist_node) {
       
   116         if (memcache_conn_is_available(conn)) {
       
   117             // remove the req from the queue and execute it
       
   118             TAILQ_REMOVE(&server->req_queue, req, reqqueue_node);
       
   119             
       
   120             // this will take care of any error handling by itself
       
   121             memcache_conn_do_req(conn, req);
       
   122             
       
   123             // if that was the last req, return, otherwise continue
       
   124             if ((req = TAILQ_FIRST(&server->req_queue)) == NULL)
       
   125                 return;
       
   126         }
       
   127     }
       
   128     
       
   129     // no idle connections remaining, try and grow if applicable
       
   130     memcache_server_grow_connpool(server);
       
   131 }
       
   132 
    92 void memcache_server_conn_ready (struct memcache_server *server, struct memcache_conn *conn) {
   133 void memcache_server_conn_ready (struct memcache_server *server, struct memcache_conn *conn) {
    93     assert(server == conn->server);
   134     assert(server == conn->server);
    94 
   135     
    95     // do we have any queued requests waiting?
   136     // grab the next queued request
    96     struct memcache_req *req = server->req_queue.tqh_first;
   137     memache_server_dequeue(server);
    97 
       
    98     if (req) {
       
    99         // remove it from the queue and execute it
       
   100         TAILQ_REMOVE(&server->req_queue, req, reqqueue_node);
       
   101         
       
   102         // this will take care of any error handling by itself
       
   103         memcache_conn_do_req(conn, req);
       
   104     }
       
   105 }
   138 }
   106 
   139 
   107 void memcache_server_conn_dead (struct memcache_server *server, struct memcache_conn *conn) {
   140 void memcache_server_conn_dead (struct memcache_server *server, struct memcache_conn *conn) {
   108     assert(server == conn->server);
   141     assert(server == conn->server);
   109 
   142 
   110     // XXX: reconnect/error out requests?
       
   111     
       
   112     // remove it from the list
   143     // remove it from the list
   113     LIST_REMOVE(conn, connlist_node);
   144     LIST_REMOVE(conn, connlist_node);
   114 
   145 
   115     // free it
   146     // free it
   116     memcache_conn_free(conn);
   147     memcache_conn_free(conn);
       
   148 
       
   149     // this should grow the connpool back again
       
   150     memache_server_dequeue(server);
   117 }
   151 }
   118 
   152