terom@40: terom@40: #include terom@40: #include terom@40: terom@40: #include "request.h" terom@40: #include "memcache.h" terom@40: #include "../common.h" terom@40: terom@44: struct memcache_req *memcache_req_alloc (struct memcache *mc, enum memcache_command cmd_type, const struct memcache_key *key, const struct memcache_obj *obj, const struct memcache_buf *buf, void *cb_arg) { terom@40: struct memcache_req *req = NULL; terom@44: terom@44: // ensure key is provided terom@44: assert(key != NULL); terom@40: terom@40: // allocate it terom@40: if ((req = calloc(1, sizeof(*req))) == NULL) terom@40: ERROR("calloc"); terom@40: terom@40: // state terom@41: req->state = MEMCACHE_STATE_INVALID; terom@40: terom@46: // key length? terom@46: if (key->len == 0) terom@46: req->key.len = strlen(key->buf); terom@46: else terom@46: req->key.len = key->len; terom@46: terom@46: if (req->key.len == 0) terom@46: ERROR("zero-length key"); terom@46: terom@40: // copy the key terom@46: if ((req->key.buf = malloc(req->key.len)) == NULL) terom@40: ERROR("malloc key buf"); terom@40: terom@46: memcpy(req->key.buf, key->buf, req->key.len); terom@44: terom@44: // copy the obj if provided terom@44: if (obj) { terom@44: memcpy(&req->obj, obj, sizeof(req->obj)); terom@44: req->have_obj = 1; terom@44: } terom@44: terom@46: // copy the buf if provided, and reset the offset to zero terom@44: if (buf) { terom@46: // ensure that it is a valid buffer terom@46: assert(buf->data && buf->len > 0 && buf->offset == buf->len); terom@46: terom@44: memcpy(&req->buf, buf, sizeof(req->buf)); terom@44: req->have_buf = 1; terom@46: terom@46: // set offset to zero terom@46: req->buf.offset = 0; terom@44: } terom@40: terom@41: // store the other data terom@40: req->mc = mc; terom@41: req->cmd_type = cmd_type; terom@40: req->cb_arg = cb_arg; terom@40: terom@40: // success terom@40: return req; terom@40: terom@40: error: terom@40: if (req) { terom@40: free(req->key.buf); terom@40: free(req); terom@40: } terom@40: terom@40: return NULL; terom@40: } terom@40: terom@44: // accessors terom@44: enum memcache_req_state memcache_req_state (struct memcache_req *req) { terom@44: return req->state; terom@44: } terom@44: terom@44: enum memcache_command memcache_req_cmd (struct memcache_req *req) { terom@44: return req->cmd_type; terom@44: } terom@44: terom@44: enum memcache_reply memcache_req_reply (struct memcache_req *req) { terom@44: return req->reply_type; terom@44: } terom@44: terom@44: const struct memcache_key *keymemcache_req_key (struct memcache_req *req) { terom@44: return &req->key; terom@44: } terom@44: terom@44: const struct memcache_obj *memcache_req_obj (struct memcache_req *req) { terom@44: return req->have_obj ? &req->obj : NULL; terom@44: } terom@44: terom@44: const struct memcache_buf *memcache_req_buf (struct memcache_req *req) { terom@44: return req->have_buf ? &req->buf : NULL; terom@44: } terom@44: terom@44: // events terom@42: static void _memcache_req_notify (struct memcache_req *req) { terom@42: req->mc->cb_fn(req, req->cb_arg); terom@40: } terom@40: terom@42: void memcache_req_queued (struct memcache_req *req) { terom@42: req->state = MEMCACHE_STATE_QUEUED; terom@42: terom@42: // _memcache_req_notify(req); terom@42: } terom@42: terom@42: void memcache_req_send (struct memcache_req *req) { terom@42: req->state = MEMCACHE_STATE_SEND; terom@42: terom@42: // _memcache_req_notify(req); terom@42: } terom@42: terom@44: void memcache_req_recv (struct memcache_req *req, enum memcache_reply reply_type) { terom@42: req->state = MEMCACHE_STATE_REPLY; terom@42: req->reply_type = reply_type; terom@42: terom@44: // we must surely have a valid obj now terom@44: req->have_obj = 1; terom@44: terom@42: _memcache_req_notify(req); terom@42: } terom@42: terom@43: void memcache_req_data (struct memcache_req *req) { terom@43: assert(req->state == MEMCACHE_STATE_REPLY || req->state == MEMCACHE_STATE_REPLY_DATA); terom@43: terom@43: req->state = MEMCACHE_STATE_REPLY_DATA; terom@44: terom@44: // we must surely have a valid buf now terom@44: req->have_buf = 1; terom@43: terom@43: _memcache_req_notify(req); terom@43: } terom@43: terom@42: void memcache_req_done (struct memcache_req *req) { terom@43: // make sure we are in the REPLY/REPLY_DATA state terom@43: assert(req->state == MEMCACHE_STATE_REPLY || req->state == MEMCACHE_STATE_REPLY_DATA); terom@44: terom@44: // are we supposed to have data? terom@44: if (req->buf.data) { terom@44: // make sure we really have the full data, if applicable terom@44: assert(req->buf.offset == req->buf.len); terom@44: terom@44: // yes... terom@44: req->have_buf = 1; terom@43: terom@44: // have data terom@44: req->state = MEMCACHE_STATE_DATA_DONE; terom@44: terom@44: } else { terom@44: // no data terom@44: req->state = MEMCACHE_STATE_DONE; terom@44: } terom@42: terom@42: // forget the connection terom@42: req->conn = NULL; terom@43: terom@44: _memcache_req_notify(req); terom@43: } terom@42: terom@43: void memcache_req_error (struct memcache_req *req) { terom@43: // forget our connection terom@43: req->conn = NULL; terom@43: terom@43: req->state = MEMCACHE_STATE_ERROR; terom@43: terom@43: _memcache_req_notify(req); terom@40: } terom@40: terom@40: void memcache_req_free (struct memcache_req *req) { terom@40: // must be unused terom@40: assert(req->conn == NULL); terom@43: assert(req->state == MEMCACHE_STATE_INVALID || req->state == MEMCACHE_STATE_ERROR || req->state == MEMCACHE_STATE_DONE || req->state == MEMCACHE_STATE_DATA_DONE); terom@40: terom@40: free(req->key.buf); terom@40: free(req); terom@40: } terom@40: