static void req_process_set(struct context *ctx, struct conn *conn, struct msg *msg) { uint8_t *key, nkey, cid; struct item *it; key = msg->key_start; nkey = (uint8_t)(msg->key_end - msg->key_start); cid = item_slabcid(nkey, msg->vlen); if (cid == SLABCLASS_INVALID_ID) { rsp_send_error(ctx, conn, msg, MSG_RSP_CLIENT_ERROR, EINVAL); return; } itemx_removex(msg->hash, msg->md); it = item_get(key, nkey, cid, msg->vlen, 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; } mbuf_copy_to(&msg->mhdr, msg->value, item_data(it), msg->vlen); rsp_send_status(ctx, conn, msg, MSG_RSP_STORED); }
static void asc_process_flushall(struct conn *c, struct token *token, int ntoken) { struct bound *t = &ntoken_bound[REQ_FLUSHALL]; int32_t exptime_int; time_t exptime; time_update(); asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } if (ntoken == t->b[c->noreply].min) { settings.oldest_live = time_now() - 1; item_flush_expired(); asc_write_ok(c); return; } if (!mc_strtol(token[TOKEN_SUBCOMMAND].val, &exptime_int)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d with " "invalid numeric value '%.*s'", c->sd, c->req_type, token[TOKEN_SUBCOMMAND].len, token[TOKEN_SUBCOMMAND].val); asc_write_client_error(c); return; } exptime = (time_t)exptime_int; /* * If exptime is zero time_reltime() would return zero too, and * time_reltime(exptime) - 1 would overflow to the max unsigned value. * So we process exptime == 0 the same way we do when no delay is * given at all. */ if (exptime > 0) { settings.oldest_live = time_reltime(exptime) - 1; } else { /* exptime == 0 */ settings.oldest_live = time_now() - 1; } item_flush_expired(); asc_write_ok(c); }
static void asc_process_update(struct conn *c, struct token *token, int ntoken) { char *key; size_t nkey; uint32_t flags, vlen; int32_t exptime_int; time_t exptime; uint64_t req_cas_id = 0; struct item *it; bool handle_cas; req_type_t type; uint8_t id; asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } type = c->req_type; handle_cas = (type == REQ_CAS) ? true : false; key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_FLAGS].val, &flags)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid flags '%.*s'", c->sd, c->req_type, token[TOKEN_FLAGS].len, token[TOKEN_FLAGS].val); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_EXPIRY].val, &exptime_int)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid expiry '%.*s'", c->sd, c->req_type, token[TOKEN_EXPIRY].len, token[TOKEN_EXPIRY].val); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_VLEN].val, &vlen)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid vlen '%.*s'", c->sd, c->req_type, token[TOKEN_VLEN].len, token[TOKEN_VLEN].val); asc_write_client_error(c); return; } id = item_slabid(nkey, vlen); if (id == SLABCLASS_INVALID_ID) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "slab id out of range for key size %"PRIu8" and value size " "%"PRIu32, c->sd, c->req_type, nkey, vlen); asc_write_client_error(c); return; } exptime = (time_t)exptime_int; /* does cas value exist? */ if (handle_cas) { if (!mc_strtoull(token[TOKEN_CAS].val, &req_cas_id)) { log_debug(LOG_NOTICE, "client error on c %d for req of type %d and " "invalid cas '%.*s'", c->sd, c->req_type, token[TOKEN_CAS].len, token[TOKEN_CAS].val); asc_write_client_error(c); return; } } it = item_alloc(id, key, nkey, flags, time_reltime(exptime), vlen); if (it == NULL) { log_warn("server error on c %d for req of type %d because of oom in " "storing item", c->sd, c->req_type); asc_write_server_error(c); /* swallow the data line */ c->write_and_go = CONN_SWALLOW; c->sbytes = vlen + CRLF_LEN; /* * Avoid stale data persisting in cache because we failed alloc. * Unacceptable for SET. Anywhere else too? * * FIXME: either don't delete anything or should be unacceptable for * all but add. */ if (type == REQ_SET) { it = item_get(key, nkey); if (it != NULL) { item_delete(it); } } return; } item_set_cas(it, req_cas_id); c->item = it; c->ritem = item_data(it); c->rlbytes = it->nbyte + CRLF_LEN; conn_set_state(c, CONN_NREAD); }
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); }
static void asc_process_update(struct conn *c, struct token *token, int ntoken) { char *key; size_t nkey; unsigned int flags; int32_t exptime_int; time_t exptime; int vlen; uint64_t req_cas_id = 0; struct item *it; bool handle_cas; req_type_t type; asc_set_noreply_maybe(c, token, ntoken); if (!asc_ntoken_valid(c, ntoken)) { log_hexdump(LOG_INFO, c->req, c->req_len, "client error on c %d for " "req of type %d with %d invalid tokens", c->sd, c->req_type, ntoken); asc_write_client_error(c); return; } type = c->req_type; handle_cas = (type == REQ_CAS) ? true : false; key = token[TOKEN_KEY].val; nkey = token[TOKEN_KEY].len; if (nkey > KEY_MAX_LEN) { log_debug(LOG_INFO, "client error on c %d for req of type %d and %d " "length key", c->sd, c->req_type, nkey); asc_write_client_error(c); return; } if (!mc_strtoul(token[TOKEN_FLAGS].val, (uint32_t *)&flags)) { log_debug(LOG_INFO, "client error on c %d for req of type %d and " "invalid flags '%.*s'", c->sd, c->req_type, token[TOKEN_FLAGS].len, token[TOKEN_FLAGS].val); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_EXPIRY].val, &exptime_int)) { log_debug(LOG_INFO, "client error on c %d for req of type %d and " "invalid expiry '%.*s'", c->sd, c->req_type, token[TOKEN_EXPIRY].len, token[TOKEN_EXPIRY].val); asc_write_client_error(c); return; } if (!mc_strtol(token[TOKEN_VLEN].val, (int32_t *)&vlen)) { log_debug(LOG_INFO, "client error on c %d for req of type %d and " "invalid vlen '%.*s'", c->sd, c->req_type, token[TOKEN_VLEN].len, token[TOKEN_VLEN].val); asc_write_client_error(c); return; } exptime = (time_t)exptime_int; /* does cas value exist? */ if (handle_cas) { if (!mc_strtoull(token[TOKEN_CAS].val, &req_cas_id)) { log_debug(LOG_INFO, "client error on c %d for req of type %d and " "invalid cas '%.*s'", c->sd, c->req_type, token[TOKEN_CAS].len, token[TOKEN_CAS].val); asc_write_client_error(c); return; } } if (vlen < 0) { log_debug(LOG_INFO, "client error on c %d for req of type %d and " "invalid vlen %d", c->sd, c->req_type, vlen); asc_write_client_error(c); return; } vlen += CRLF_LEN; it = item_alloc(key, nkey, flags, time_reltime(exptime), vlen); if (it == NULL) { log_debug(LOG_DEBUG, "server error on c %d for req of type %d because " "of oom in storing item", c->sd, c->req_type); asc_write_server_error(c); /* swallow the data line */ c->write_and_go = CONN_SWALLOW; c->sbytes = vlen; /* * Avoid stale data persisting in cache because we failed alloc. * Unacceptable for SET. Anywhere else too? */ if (type == REQ_SET) { it = item_get(key, nkey); if (it != NULL) { item_unlink(it); item_remove(it); } } return; } item_set_cas(it, req_cas_id); c->item = it; c->ritem = item_data(it); c->rlbytes = it->nbyte; conn_set_state(c, CONN_NREAD); }