#include <stdlib.h>
#include <assert.h>
#include "server.h"
#include "connection.h"
#include "request.h"
#include "../memcache.h"
#include "../common.h"
struct memcache_server *memcache_server_alloc (struct config_endpoint *endpoint, int max_connections) {
struct memcache_server *server = NULL;
if ((server = calloc(1, sizeof(*server))) == NULL)
ERROR("calloc");
// store the vars
server->endpoint = endpoint;
server->max_connections = max_connections;
// grow connpool so as to have a connection ready
if (memcache_server_grow_connpool(server))
ERROR("error opening initial connection");
// success
return server;
error:
free(server);
return NULL;
}
int memcache_server_grow_connpool (struct memcache_server *server) {
struct memcache_conn *conn;
int count;
// count connections
for (count = 0, conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next, count++) ;
// room for more?
if (count < server->max_connections) {
// create a new one
if ((conn = memcache_conn_open(server)) == NULL)
return -1;
// enlist it
LIST_INSERT_HEAD(&server->conn_list, conn, connlist_node);
// the connection will call memcache_server_coon_ready once it's ready for use...
}
// success
return 0;
}
int memcache_server_add_req (struct memcache_server *server, struct memcache_req *req) {
struct memcache_conn *conn;
// look for an idle connection
for (conn = server->conn_list.lh_first; conn != NULL; conn = conn->connlist_node.le_next) {
if (conn->req == NULL) {
// we found an idle connection
break;
}
}
if (conn != NULL) {
// we found an available connection
return memcache_conn_do_req(conn, req);
} else {
// enqueue the request until a connection is available
// XXX: queue size limits
TAILQ_INSERT_TAIL(&server->req_queue, req, reqqueue_node);
return 0;
}
}
void memcache_server_conn_ready (struct memcache_server *server, struct memcache_conn *conn) {
assert(server == conn->server);
// do we have any queued requests waiting?
struct memcache_req *req = server->req_queue.tqh_first;
if (req) {
// remove it from the queue and execute it
TAILQ_REMOVE(&server->req_queue, req, reqqueue_node);
if (memcache_conn_do_req(conn, req)) {
WARNING("processing enqueued request failed");
// XXX: error handling for req
}
}
}