static struct item* _item_alloc(uint8_t id, char *key, uint16_t nkey, int exptime, char *value, uint32_t nbyte) { struct item *it; struct item *uit; assert(id >= SLABCLASS_MIN_ID && id <= SLABCLASS_MAX_ID); it = item_get_from_lruq(id); if (it != NULL && item_expired(it)) { item_reuse(it); goto done; } uit = (settings.evict_opt & EVICT_LRU)? it : NULL; it = slab_get_item(id); if (it != NULL) { goto done; } if (uit != NULL) { it = uit; item_reuse(it); goto done; } return NULL; done: assert(it->id == id); assert(!item_is_linked(it)); assert(!item_is_slabbed(it)); assert(it->offset != 0); assert(it->refcount == 0); it->flags = 0; it->nbyte = nbyte; it->exptime = exptime + time_now(); it->nkey = nkey; memcpy(item_key(it), key, nkey); memcpy(item_key(it) + nkey, value, nbyte); return it; }
static void req_process_add(struct context *ctx, struct conn *conn, struct msg *msg) { struct itemx *itx; struct item *it; /* add, adds only if the mapping is not present */ itx = itemx_getx(msg->hash, msg->md); if (itx != NULL) { it = slab_read_item(itx->sid, itx->offset); /* if the item hasn't expired yet */ if(!item_expired(it)) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_STORED); return; } } req_process_set(ctx, conn, msg); }
static struct item* item_get_from_lruq(uint8_t id) { struct item *it; struct item *uit; uint32_t tries; if (!settings.use_lruq) { return NULL; } for (tries = ITEM_LRUQ_MAX_TRIES, it = TAILQ_FIRST(&item_lruq[id]), uit = NULL; it != NULL && tries > 0; tries--, it = TAILQ_NEXT(it, i_tqe)) { if (it->refcount != 0) { continue; } if (item_expired(it)) { return it; } else if (uit == NULL) { uit = it; } } return uit; }
static void req_process_get(struct context *ctx, struct conn *conn, struct msg *msg) { struct itemx *itx; struct item *it; itx = itemx_getx(msg->hash, msg->md); if (itx == NULL) { msg_type_t type; /* * On a miss, we send a "END\r\n" response, unless the request * is an intermediate fragment in a fragmented request. */ if (msg->frag_id == 0 || msg->last_fragment) { type = MSG_RSP_END; } else { type = MSG_EMPTY; } rsp_send_status(ctx, conn, msg, type); return; } /* * On a hit, we read the item with address [sid, offset] and respond * with item value if the item hasn't expired yet. */ it = slab_read_item(itx->sid, itx->offset); if (it == NULL) { rsp_send_error(ctx, conn, msg, MSG_RSP_SERVER_ERROR, errno); return; } if (item_expired(it)) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_FOUND); return; } rsp_send_value(ctx, conn, msg, it, itx->cas); }
static void req_process_replace(struct context *ctx, struct conn *conn, struct msg *msg) { struct itemx *itx; struct item *it; /* replace, only replaces if the mapping is present */ itx = itemx_getx(msg->hash, msg->md); if (itx == NULL) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_STORED); return; } /* if the item has expired */ it = slab_read_item(itx->sid, itx->offset); if(item_expired(it)) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_STORED); return; } req_process_set(ctx, conn, msg); }
static void req_process_num(struct context *ctx, struct conn *conn, struct msg *msg) { rstatus_t status; uint8_t *key, nkey, cid; struct item *it; struct itemx *itx; uint64_t cnum, nnum; char numstr[FC_UINT64_MAXLEN]; int n; key = msg->key_start; nkey = (uint8_t)(msg->key_end - msg->key_start); /* 1). look up existing itemx */ itx = itemx_getx(msg->hash, msg->md); if (itx == NULL) { /* 2a). miss -> return NOT_FOUND */ rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_FOUND); return; } /* 2b). hit -> read existing item into it */ it = slab_read_item(itx->sid, itx->offset); if (it == NULL) { rsp_send_error(ctx, conn, msg, MSG_RSP_SERVER_ERROR, errno); return; } if (item_expired(it)) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_FOUND); return; } /* 3). sanity check item data to be a number */ status = fc_atou64(item_data(it), it->ndata, &cnum); if (status != FC_OK) { rsp_send_error(ctx, conn, msg, MSG_RSP_CLIENT_ERROR, EINVAL); return; } /* 4). remove existing itemx of it */ itemx_removex(msg->hash, msg->md); /* 5). compute the new incr/decr number nnum and numstr */ if (msg->type == MSG_REQ_INCR) { nnum = cnum + msg->num; } else { if (cnum < msg->num) { nnum = 0; } else { nnum = cnum - msg->num; } } n = fc_scnprintf(numstr, sizeof(numstr), "%"PRIu64"", nnum); /* 6). alloc new item that can hold n worth of bytes */ cid = item_slabcid(nkey, n); ASSERT(cid != SLABCLASS_INVALID_ID); it = item_get(key, nkey, cid, n, time_reltime(msg->expiry), msg->flags, msg->md, msg->hash); if (it == NULL) { rsp_send_error(ctx, conn, msg, MSG_RSP_SERVER_ERROR, ENOMEM); return; } /* 7). copy numstr to it */ fc_memcpy(item_data(it), numstr, n); rsp_send_num(ctx, conn, msg, it); }
static void req_process_concat(struct context *ctx, struct conn *conn, struct msg *msg) { uint8_t *key, nkey, cid; struct item *oit, *it; uint32_t ndata; struct itemx *itx; key = msg->key_start; nkey = (uint8_t)(msg->key_end - msg->key_start); /* 1). look up existing itemx */ itx = itemx_getx(msg->hash, msg->md); if (itx == NULL) { /* 2a). miss -> return NOT_STORED */ rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_STORED); return; } /* 2b). hit -> read existing item into oit */ oit = slab_read_item(itx->sid, itx->offset); if (oit == NULL) { rsp_send_error(ctx, conn, msg, MSG_RSP_SERVER_ERROR, errno); return; } if (item_expired(oit)) { rsp_send_status(ctx, conn, msg, MSG_RSP_NOT_STORED); return; } ndata = msg->vlen + oit->ndata; cid = item_slabcid(nkey, ndata); if (cid == SLABCLASS_INVALID_ID) { rsp_send_error(ctx, conn, msg, MSG_RSP_CLIENT_ERROR, EINVAL); return; } /* 3). remove existing itemx of oit */ itemx_removex(msg->hash, msg->md); /* 4). alloc new item that can hold ndata worth of bytes */ it = item_get(key, nkey, cid, ndata, time_reltime(msg->expiry), msg->flags, msg->md, msg->hash); if (it == NULL) { rsp_send_error(ctx, conn, msg, MSG_RSP_SERVER_ERROR, ENOMEM); return; } /* 5). copy data from msg to head or tail of new item it */ switch (msg->type) { case MSG_REQ_PREPEND: mbuf_copy_to(&msg->mhdr, msg->value, item_data(it), msg->vlen); fc_memcpy(item_data(it) + msg->vlen, item_data(oit), oit->ndata); break; case MSG_REQ_APPEND: fc_memcpy(item_data(it), item_data(oit), oit->ndata); mbuf_copy_to(&msg->mhdr, msg->value, item_data(it) + oit->ndata, msg->vlen); break; default: NOT_REACHED(); } rsp_send_status(ctx, conn, msg, MSG_RSP_STORED); }