void item_update(struct item *it, const struct bstring *val) { ASSERT(item_slabid(it->klen, val->len, it->olen) == it->id); it->vlen = val->len; cc_memcpy(item_data(it), val->data, val->len); item_set_cas(it); log_verb("update it %p of id %"PRIu8, it, it->id); }
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); }
item_rstatus_e item_annex(struct item *oit, const struct bstring *key, const struct bstring *val, bool append) { item_rstatus_e status = ITEM_OK; struct item *nit = NULL; uint8_t id; uint32_t ntotal = oit->vlen + val->len; id = item_slabid(oit->klen, ntotal, oit->olen); if (id == SLABCLASS_INVALID_ID) { log_info("client error: annex operation results in oversized item with" "key size %"PRIu8" old value size %"PRIu32" and new value " "size %"PRIu32, oit->klen, oit->vlen, ntotal); return ITEM_EOVERSIZED; } if (append) { /* if it is large enough to hold the extra data and left-aligned, * which is the default behavior, we copy the delta to the end of * the existing data. Otherwise, allocate a new item and store the * payload left-aligned. */ if (id == oit->id && !(oit->is_raligned)) { cc_memcpy(item_data(oit) + oit->vlen, val->data, val->len); oit->vlen = ntotal; INCR_N(slab_metrics, item_keyval_byte, val->len); INCR_N(slab_metrics, item_val_byte, val->len); item_set_cas(oit); } else { status = _item_alloc(&nit, oit->klen, ntotal, oit->olen); if (status != ITEM_OK) { log_debug("annex failed due to failure to allocate new item"); return status; } _copy_key_item(nit, oit); nit->expire_at = oit->expire_at; nit->create_at = time_proc_sec(); item_set_cas(nit); /* value is left-aligned */ cc_memcpy(item_data(nit), item_data(oit), oit->vlen); cc_memcpy(item_data(nit) + oit->vlen, val->data, val->len); nit->vlen = ntotal; item_insert(nit, key); } } else { /* if oit is large enough to hold the extra data and is already * right-aligned, we copy the delta to the front of the existing * data. Otherwise, allocate a new item and store the payload * right-aligned, assuming more prepends will happen in the future. */ if (id == oit->id && oit->is_raligned) { cc_memcpy(item_data(oit) - val->len, val->data, val->len); oit->vlen = ntotal; INCR_N(slab_metrics, item_keyval_byte, val->len); INCR_N(slab_metrics, item_val_byte, val->len); item_set_cas(oit); } else { status = _item_alloc(&nit, oit->klen, ntotal, oit->olen); if (status != ITEM_OK) { log_debug("annex failed due to failure to allocate new item"); return status; } _copy_key_item(nit, oit); nit->expire_at = oit->expire_at; nit->create_at = time_proc_sec(); item_set_cas(nit); /* value is right-aligned */ nit->is_raligned = 1; cc_memcpy(item_data(nit) - ntotal, val->data, val->len); cc_memcpy(item_data(nit) - oit->vlen, item_data(oit), oit->vlen); nit->vlen = ntotal; item_insert(nit, key); } } log_verb("annex to it %p of id %"PRIu8", new it at %p", oit, oit->id, nit ? oit : nit); return status; }