terom@38: terom@38: #include terom@38: #include terom@38: terom@38: #include "server.h" terom@38: #include "connection.h" terom@38: #include "request.h" terom@38: #include "../memcache.h" terom@38: #include "../common.h" terom@38: terom@38: struct memcache_server *memcache_server_alloc (struct config_endpoint *endpoint, int max_connections) { terom@38: struct memcache_server *server = NULL; terom@38: terom@38: if ((server = calloc(1, sizeof(*server))) == NULL) terom@38: ERROR("calloc"); terom@38: terom@38: // store the vars terom@38: server->endpoint = endpoint; terom@38: server->max_connections = max_connections; terom@46: terom@46: // init lists terom@46: LIST_INIT(&server->conn_list); terom@46: TAILQ_INIT(&server->req_queue); terom@38: terom@38: // grow connpool so as to have a connection ready terom@38: if (memcache_server_grow_connpool(server)) terom@38: ERROR("error opening initial connection"); terom@38: terom@38: // success terom@38: return server; terom@38: terom@38: error: terom@38: free(server); terom@38: terom@38: return NULL; terom@38: } terom@38: terom@38: int memcache_server_grow_connpool (struct memcache_server *server) { terom@38: struct memcache_conn *conn; terom@38: int count; terom@38: terom@38: // count connections terom@38: for (count = 0, conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next, count++) ; terom@38: terom@38: // room for more? terom@38: if (count < server->max_connections) { terom@38: // create a new one terom@38: if ((conn = memcache_conn_open(server)) == NULL) terom@38: return -1; terom@38: terom@38: // enlist it terom@38: LIST_INSERT_HEAD(&server->conn_list, conn, connlist_node); terom@38: terom@38: // the connection will call memcache_server_coon_ready once it's ready for use... terom@38: } terom@38: terom@38: // success terom@38: return 0; terom@38: } terom@38: terom@38: int memcache_server_add_req (struct memcache_server *server, struct memcache_req *req) { terom@38: struct memcache_conn *conn; terom@38: terom@38: // look for an idle connection terom@38: for (conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next) { terom@39: if (memcache_conn_is_available(conn)) { terom@38: // we found an idle connection terom@38: break; terom@38: } terom@38: } terom@38: terom@38: if (conn != NULL) { terom@38: // we found an available connection terom@43: // if the request fails, then we will know via conn_dead terom@43: memcache_conn_do_req(conn, req); terom@43: terom@43: return 0; terom@38: terom@38: } else { terom@38: // enqueue the request until a connection is available terom@38: // XXX: queue size limits terom@38: terom@38: TAILQ_INSERT_TAIL(&server->req_queue, req, reqqueue_node); terom@42: terom@42: // notify the req terom@42: memcache_req_queued(req); terom@38: terom@38: return 0; terom@38: } terom@38: } terom@38: terom@38: void memcache_server_conn_ready (struct memcache_server *server, struct memcache_conn *conn) { terom@38: assert(server == conn->server); terom@38: terom@38: // do we have any queued requests waiting? terom@38: struct memcache_req *req = server->req_queue.tqh_first; terom@38: terom@38: if (req) { terom@38: // remove it from the queue and execute it terom@38: TAILQ_REMOVE(&server->req_queue, req, reqqueue_node); terom@38: terom@43: // this will take care of any error handling by itself terom@43: memcache_conn_do_req(conn, req); terom@38: } terom@38: } terom@38: terom@39: void memcache_server_conn_dead (struct memcache_server *server, struct memcache_conn *conn) { terom@39: assert(server == conn->server); terom@39: terom@39: // XXX: reconnect/error out requests? terom@39: terom@39: // remove it from the list terom@39: LIST_REMOVE(conn, connlist_node); terom@39: terom@39: // free it terom@39: memcache_conn_free(conn); terom@39: } terom@39: