void btree_page_data::remove_items( const int item_count, // In: Number of records to remove const w_keystr_t &high) // In: high fence after record removal { // Use this function with caution // A special helper function to remove 'item_count' largest items from the storage // this function is only used by full logging page rebalance restart operation // to recover the source page after a system crash // the caller resets the fence keys on source page which eliminate some // of the records from source page // this function removes the largest 'item_count' items from the page // because they belong to destination page after the rebalance // After the removal, item count changed but no change to ghost count w_assert1(btree_level >= 1); w_assert1(nitems > item_count); // Must have at least one record which is the fency key record w_assert3(_items_are_consistent()); if ((0 == item_count) || (1 == nitems)) // If 1 == nitems, we only have a fence key record return; DBGOUT3( << "btree_page_data::reset_item_count - before deletion item count: " << nitems << ", new high fence key: " << high); int remaining = item_count; char* high_key_p = (char *)high.buffer_as_keystr(); size_t high_key_length = (size_t)high.get_length_as_keystr(); while (0 < remaining) { w_assert1(1 < nitems); // Find the records with key >= new high fence key and delete them int item_index = 1; // Start with index 1 since 0 is for the fence key record uint16_t* key_length;; size_t item_len; int cmp; const int data_offset = sizeof(uint16_t); // To skipover the portion which contains the size of variable data for (int i = item_index; i < nitems; ++i) { key_length = (uint16_t*)item_data(i); item_len = *key_length++; cmp = ::memcmp(high_key_p, item_data(i)+data_offset, (high_key_length<=item_len)? high_key_length : item_len); if ((0 > cmp) || ((0 == cmp) && (high_key_length <= item_len))) { // The item is larger than the new high fence key or the same as high fence key (high fence is ghost) DBGOUT3( << "btree_page_data::reset_item_count - delete record index: " << i); // Delete the item, which changes nitems but no change to nghosts // therefore break out the loop and start the loop again if we have more items to remove delete_item(i); break; } } --remaining; }
static void conf_choice(struct menu *menu) { const char *prompt = _(menu_get_prompt(menu)); struct menu *child; struct symbol *active; active = sym_get_choice_value(menu->sym); while (1) { int res; int selected; item_reset(); current_menu = menu; for (child = menu->list; child; child = child->next) { if (!menu_is_visible(child)) continue; if (child->sym) item_make("%s", _(menu_get_prompt(child))); else { item_make("*** %s ***", _(menu_get_prompt(child))); item_set_tag(':'); } item_set_data(child); if (child->sym == active) item_set_selected(1); if (child->sym == sym_get_choice_value(menu->sym)) item_set_tag('X'); } dialog_clear(); res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), _(radiolist_instructions), 15, 70, 6); selected = item_activate_selected(); switch (res) { case 0: if (selected) { child = item_data(); if (!child->sym) break; sym_set_tristate_value(child->sym, yes); } return; case 1: if (selected) { child = item_data(); show_help(child); active = child->sym; } else show_help(menu); break; case KEY_ESC: return; case -ERRDISPLAYTOOSMALL: return; } } }
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); }
void cmd_list_create(struct response *rsp, struct request *req, struct command *cmd) { struct item *it; struct bstring *key = _get_key(req); struct element *reply = (struct element *)array_push(rsp->token); INCR(process_metrics, list_create); it = _add_key(rsp, key); if (it == NULL) { log_debug("command '%.*s' '%.*s' failed: cannot store", cmd->bstr.len, cmd->bstr.data, key->len, key->data); return; } /* initialize data structure */ ziplist_reset((ziplist_p)item_data(it)); it->vlen = ZIPLIST_HEADER_SIZE; /* link into index */ item_insert(it, key); rsp->type = reply->type = ELEM_STR; reply->bstr = str2bstr(RSP_OK); log_verb("command '%.*s' '%.*s' succeeded", cmd->bstr.len, cmd->bstr.data, key->len, key->data); }
/** * Return an item if it hasn't been marked as expired, lazily expiring * item as-and-when needed */ struct item * item_get(const struct bstring *key) { struct item *it; it = hashtable_get(key->data, key->len, hash_table); if (it == NULL) { log_verb("get it '%.*s' not found", key->len, key->data); return NULL; } log_verb("get it key %.*s val %.*s", key->len, key->data, it->vlen, item_data(it)); if (_item_expired(it)) { log_verb("get it '%.*s' expired and nuked", key->len, key->data); _item_unlink(it); _item_dealloc(&it); return NULL; } log_verb("get it %p of id %"PRIu8, it, it->id); return it; }
/* * Build the response. Each hit adds three elements to the outgoing * reponse vector, viz: * "VALUE " * key * " " + flags + " " + data length + "\r\n" + data (with \r\n) */ static rstatus_t asc_respond_get(struct conn *c, unsigned valid_key_iter, struct item *it, bool return_cas) { rstatus_t status; char *cas_suffix = NULL; int cas_suffix_len = 0; int total_len = it->nkey + it->nsuffix + it->nbyte; if (return_cas) { status = asc_create_cas_suffix(c, valid_key_iter, &cas_suffix); if (status != MC_OK) { return status; } cas_suffix_len = snprintf(cas_suffix, CAS_SUFFIX_SIZE, " %"PRIu64, item_cas(it)); } status = conn_add_iov(c, "VALUE ", sizeof("VALUE ") - 1); if (status != MC_OK) { return status; } status = conn_add_iov(c, item_key(it), it->nkey); if (status != MC_OK) { return status; } status = conn_add_iov(c, item_suffix(it), it->nsuffix - CRLF_LEN); if (status != MC_OK) { return status; } if (return_cas) { status = conn_add_iov(c, cas_suffix, cas_suffix_len); if (status != MC_OK) { return status; } total_len += cas_suffix_len; } status = conn_add_iov(c, CRLF, CRLF_LEN); if (status != MC_OK) { return status; } status = conn_add_iov(c, item_data(it), it->nbyte); if (status != MC_OK) { return status; } klog_write(c->peer, c->req_type, item_key(it), it->nkey, 0, total_len); return MC_OK; }
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); }
void item_backfill(struct item *it, const struct bstring *val) { ASSERT(it != NULL); cc_memcpy(item_data(it) + it->vlen, val->data, val->len); it->vlen += val->len; log_verb("backfill it %p with %"PRIu32" bytes, now %"PRIu32" bytes total", it, val->len, it->vlen); }
int main (int argc, const char * argv[]) { struct settings *settings = local_config(); settings->hash_power = 0; settings->prealloc = true; settings->evict_opt = EVICT_LRU; settings->maxbytes = 200 * 1024 * 1024; settings->slab_size = 1024 * 1024; settings->use_freeq = true; settings->use_lruq = true; settings->profile_last_id = 12; int i = 0, j = 0, n = 0; for (i = 1; i < 13; i++) { settings->profile[i] = 100 * i; } bool result = local_start(); if (result) printf("cache started\n"); else { printf("cache started fail\n"); return 1; } char *key = (char*)malloc(8); char *value = (char*)malloc(900); for (i = 0; i < 10000; i++) { for (j = 0; j < 10000; j++) { int *ptr = (int*)key; *ptr = i; *(ptr++) = j; n = i + j; n = (n % 9) * 100 + 50; ptr = (int*)value; *ptr = i; *(ptr + n - 4) = j; result = local_put(key, 8, 10, value, n); if (!result) { printf("cache put item fail\n"); printf("%d %d\n", i, j); return 1; } struct item *res = local_get(key, 8); if (res == NULL || res->nbyte != n) { printf("cache get item fail\n"); printf("%d %d\n", i, j); return 1; } char *data = item_data(res); if (*((int*)data) != i) { printf("cache get value fail\n"); printf("%d %d\n", i, j); return 1; } } } return 0; }
/* * We get here after reading the value in update commands. The command * is stored in c->req_type, and the item is ready in c->item. */ void asc_complete_nread(struct conn *c) { item_store_result_t ret; struct item *it; char *end; it = c->item; end = item_data(it) + it->nbyte; if (!strcrlf(end)) { log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for " "req of type %d with missing crlf", c->sd, c->req_type); asc_write_client_error(c); } else { ret = item_store(it, c->req_type, c); switch (ret) { case STORED: asc_write_stored(c); break; case EXISTS: asc_write_exists(c); break; case NOT_FOUND: asc_write_not_found(c); break; case NOT_STORED: asc_write_not_stored(c); break; default: log_warn("server error on c %d for req of type %d with unknown " "store result %d", c->sd, c->req_type, ret); asc_write_server_error(c); break; } } item_remove(c->item); c->item = NULL; }
/* TODO(yao): move this to memcache-specific location */ static void _item_define(struct item *it, const struct bstring *key, const struct bstring *val, uint8_t olen, proc_time_i expire_at) { proc_time_i expire_cap = time_delta2proc_sec(max_ttl); it->create_at = time_proc_sec(); it->expire_at = expire_at < expire_cap ? expire_at : expire_cap; item_set_cas(it); it->olen = olen; cc_memcpy(item_key(it), key->data, key->len); it->klen = key->len; if (val != NULL) { cc_memcpy(item_data(it), val->data, val->len); } it->vlen = (val == NULL) ? 0 : val->len; }
static bool _get_key(struct response *rsp, struct bstring *key) { struct item *it; it = item_get(key); if (it != NULL) { rsp->type = RSP_VALUE; rsp->key = *key; rsp->flag = item_flag(it); rsp->vcas = item_get_cas(it); rsp->vstr.len = it->vlen; rsp->vstr.data = item_data(it); log_verb("found key at %p, location %p", key, it); return true; } else { log_verb("key at %p not found", key); return false; } }
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); }
/* * Build the response. Each hit adds three elements to the outgoing * reponse vector, viz: * "VALUE " * key * " " + flags + " " + data length + "\r\n" + data (with \r\n) */ static rstatus_t asc_respond_get(struct conn *c, unsigned valid_key_iter, struct item *it, bool return_cas) { rstatus_t status; char *cas_suffix = NULL; char suffix[SUFFIX_MAX_LEN]; int sz; int total_len = 0; status = conn_add_iov(c, "VALUE ", sizeof("VALUE ") - 1); if (status != MC_OK) { return status; } status = conn_add_iov(c, item_key(it), it->nkey); if (status != MC_OK) { return status; } total_len += it->nkey; sz = snprintf(suffix, SUFFIX_MAX_LEN, " %"PRIu32" %"PRIu32, it->dataflags, it->nbyte); if (sz < 0) { return MC_ERROR; } ASSERT(sz < SUFFIX_MAX_LEN); /* or we have a corrupted item */ status = conn_add_iov(c, suffix, sz); if (status != MC_OK) { return status; } total_len += sz; if (return_cas) { status = asc_create_cas_suffix(c, valid_key_iter, &cas_suffix); if (status != MC_OK) { return status; } sz = snprintf(cas_suffix, CAS_SUFFIX_SIZE, " %"PRIu64, item_cas(it)); if (sz < 0) { return MC_ERROR; } ASSERT(sz < CAS_SUFFIX_SIZE); status = conn_add_iov(c, cas_suffix, sz); if (status != MC_OK) { return status; } total_len += sz; } status = conn_add_iov(c, CRLF, CRLF_LEN); if (status != MC_OK) { return status; } total_len += CRLF_LEN; status = conn_add_iov(c, item_data(it), it->nbyte); if (status != MC_OK) { return status; } total_len += it->nbyte; status = conn_add_iov(c, CRLF, CRLF_LEN); if (status != MC_OK) { return status; } total_len += CRLF_LEN; klog_write(c->peer, c->req_type, item_key(it), it->nkey, 0, total_len); return MC_OK; }
/* * Display a menu for choosing among a number of options */ int dialog_menu(const char *title, const char *prompt, const void *selected, int *s_scroll) { int i, j, x, y, box_x, box_y; int height, width, menu_height; int key = 0, button = 0, scroll = 0, choice = 0; int first_item = 0, max_choice; WINDOW *dialog, *menu; do_resize: height = getmaxy(stdscr); width = getmaxx(stdscr); if (height < 15 || width < 65) return -ERRDISPLAYTOOSMALL; height -= 4; width -= 5; menu_height = height - 10; max_choice = MIN(menu_height, item_count()); /* center dialog box on screen */ x = (COLS - width) / 2; y = (LINES - height) / 2; draw_shadow(stdscr, y, x, height, width); dialog = newwin(height, width, y, x); keypad(dialog, TRUE); draw_box(dialog, 0, 0, height, width, dlg.dialog.atr, dlg.border.atr); wattrset(dialog, dlg.border.atr); mvwaddch(dialog, height - 3, 0, ACS_LTEE); for (i = 0; i < width - 2; i++) waddch(dialog, ACS_HLINE); wattrset(dialog, dlg.dialog.atr); wbkgdset(dialog, dlg.dialog.atr & A_COLOR); waddch(dialog, ACS_RTEE); print_title(dialog, title, width); wattrset(dialog, dlg.dialog.atr); print_autowrap(dialog, prompt, width - 2, 1, 3); menu_width = width - 6; box_y = height - menu_height - 5; box_x = (width - menu_width) / 2 - 1; /* create new window for the menu */ menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1); keypad(menu, TRUE); /* draw a box around the menu items */ draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, dlg.menubox_border.atr, dlg.menubox.atr); if (menu_width >= 80) item_x = (menu_width - 70) / 2; else item_x = 4; /* Set choice to default item */ item_foreach() if (selected && (selected == item_data())) choice = item_n(); /* get the saved scroll info */ scroll = *s_scroll; if ((scroll <= choice) && (scroll + max_choice > choice) && (scroll >= 0) && (scroll + max_choice <= item_count())) { first_item = scroll; choice = choice - scroll; } else { scroll = 0; } if ((choice >= max_choice)) { if (choice >= item_count() - max_choice / 2) scroll = first_item = item_count() - max_choice; else scroll = first_item = choice - max_choice / 2; choice = choice - scroll; } /* Print the menu */ for (i = 0; i < max_choice; i++) { print_item(first_item + i, i, i == choice); } wnoutrefresh(menu); print_arrows(dialog, item_count(), scroll, box_y, box_x + item_x + 1, menu_height); print_buttons(dialog, height, width, 0); wmove(menu, choice, item_x + 1); wrefresh(menu); while (key != KEY_ESC) { key = wgetch(menu); if (key < 256 && isalpha(key)) key = tolower(key); if (strchr("ynmh", key)) i = max_choice; else { for (i = choice + 1; i < max_choice; i++) { item_set(scroll + i); j = first_alpha(item_str(), "YyNnMmHh"); if (key == tolower(item_str()[j])) break; } if (i == max_choice) for (i = 0; i < max_choice; i++) { item_set(scroll + i); j = first_alpha(item_str(), "YyNnMmHh"); if (key == tolower(item_str()[j])) break; } } if (i < max_choice || key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+' || key == KEY_PPAGE || key == KEY_NPAGE) { /* Remove highligt of current item */ print_item(scroll + choice, choice, FALSE); if (key == KEY_UP || key == '-') { if (choice < 2 && scroll) { /* Scroll menu down */ do_scroll(menu, &scroll, -1); print_item(scroll, 0, FALSE); } else choice = MAX(choice - 1, 0); } else if (key == KEY_DOWN || key == '+') { print_item(scroll+choice, choice, FALSE); if ((choice > max_choice - 3) && (scroll + max_choice < item_count())) { /* Scroll menu up */ do_scroll(menu, &scroll, 1); print_item(scroll+max_choice - 1, max_choice - 1, FALSE); } else choice = MIN(choice + 1, max_choice - 1); } else if (key == KEY_PPAGE) { scrollok(menu, TRUE); for (i = 0; (i < max_choice); i++) { if (scroll > 0) { do_scroll(menu, &scroll, -1); print_item(scroll, 0, FALSE); } else { if (choice > 0) choice--; } } } else if (key == KEY_NPAGE) { for (i = 0; (i < max_choice); i++) { if (scroll + max_choice < item_count()) { do_scroll(menu, &scroll, 1); print_item(scroll+max_choice-1, max_choice - 1, FALSE); } else { if (choice + 1 < max_choice) choice++; } } } else choice = i; print_item(scroll + choice, choice, TRUE); print_arrows(dialog, item_count(), scroll, box_y, box_x + item_x + 1, menu_height); wnoutrefresh(dialog); wrefresh(menu); continue; /* wait for another key press */ } switch (key) { case KEY_LEFT: case TAB: case KEY_RIGHT: button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 2 : (button > 2 ? 0 : button); print_buttons(dialog, height, width, button); wrefresh(menu); break; case ' ': case 's': case 'y': case 'n': case 'm': case '/': /* save scroll info */ *s_scroll = scroll; delwin(menu); delwin(dialog); item_set(scroll + choice); item_set_selected(1); switch (key) { case 's': return 3; case 'y': return 3; case 'n': return 4; case 'm': return 5; case ' ': return 6; case '/': return 7; } return 0; case 'h': case '?': button = 2; case '\n': *s_scroll = scroll; delwin(menu); delwin(dialog); item_set(scroll + choice); item_set_selected(1); return button; case 'e': case 'x': key = KEY_ESC; break; case KEY_ESC: key = on_key_esc(menu); break; #ifdef NCURSES_VERSION case KEY_RESIZE: on_key_resize(); delwin(menu); delwin(dialog); goto do_resize; #endif } } delwin(menu); delwin(dialog); return key; /* ESC pressed */ }
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); }
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; }
/* * Build the response. Each hit adds three elements to the outgoing * reponse vector, viz: * "VALUE " * key * " " + flags + " " + data length + "\r\n" + data (with \r\n) */ static rstatus_t asc_respond_get(struct conn *c, unsigned valid_key_iter, struct item *it, bool return_cas) { rstatus_t status; char *suffix = NULL; int sz; int total_len = 0; uint32_t nbyte = it->nbyte; char *data = item_data(it); status = conn_add_iov(c, VALUE, VALUE_LEN); if (status != MC_OK) { return status; } total_len += VALUE_LEN; status = conn_add_iov(c, item_key(it), it->nkey); if (status != MC_OK) { return status; } total_len += it->nkey; status = asc_create_suffix(c, valid_key_iter, &suffix); if (status != MC_OK) { return status; } if (return_cas) { sz = mc_snprintf(suffix, SUFFIX_MAX_LEN, " %"PRIu32" %"PRIu32" %"PRIu64, it->dataflags, nbyte, item_cas(it)); ASSERT(sz <= SUFFIX_SIZE + CAS_SUFFIX_SIZE); } else { sz = mc_snprintf(suffix, SUFFIX_MAX_LEN, " %"PRIu32" %"PRIu32, it->dataflags, nbyte); ASSERT(sz <= SUFFIX_SIZE); } if (sz < 0) { return MC_ERROR; } status = conn_add_iov(c, suffix, sz); if (status != MC_OK) { return status; } total_len += sz; status = conn_add_iov(c, CRLF, CRLF_LEN); if (status != MC_OK) { return status; } total_len += CRLF_LEN; status = conn_add_iov(c, data, nbyte); if (status != MC_OK) { return status; } total_len += nbyte; status = conn_add_iov(c, CRLF, CRLF_LEN); if (status != MC_OK) { return status; } total_len += CRLF_LEN; klog_write(c->peer, c->req_type, item_key(it), it->nkey, 0, total_len); return MC_OK; }
static void conf(struct menu *menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); struct symbol *sym; struct menu *active_menu = NULL; int res; int s_scroll = 0; while (1) { item_reset(); current_menu = menu; build_conf(menu); if (!child_count) break; if (menu == &rootmenu) { item_make("--- "); item_set_tag(':'); item_make(_(" Load an Alternate Configuration File")); item_set_tag('L'); item_make(_(" Save an Alternate Configuration File")); item_set_tag('S'); } dialog_clear(); res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), _(menu_instructions), active_menu, &s_scroll); if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) break; if (!item_activate_selected()) continue; if (!item_tag()) continue; submenu = item_data(); active_menu = item_data(); if (submenu) sym = submenu->sym; else sym = NULL; switch (res) { case 0: switch (item_tag()) { case 'm': if (single_menu_mode) submenu->data = (void *) (long) !submenu->data; else conf(submenu); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); else if (submenu->prompt->type == P_MENU) conf(submenu); break; case 's': conf_string(submenu); break; case 'L': conf_load(); break; case 'S': conf_save(); break; } break; case 2: if (sym) show_help(submenu); else show_helptext(_("README"), _(mconf_readme)); break; case 3: if (item_is_tag('t')) { if (sym_set_tristate_value(sym, yes)) break; if (sym_set_tristate_value(sym, mod)) show_textbox(NULL, setmod_text, 6, 74); } break; case 4: if (item_is_tag('t')) sym_set_tristate_value(sym, no); break; case 5: if (item_is_tag('t')) sym_set_tristate_value(sym, mod); break; case 6: if (item_is_tag('t')) sym_toggle_tristate_value(sym); else if (item_is_tag('m')) conf(submenu); break; case 7: search_conf(); break; } } }
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); }
typename item_data_type <const item <S, T> >::type& item_data(const item <S, T>& i) { return item_data(i.data); };
typename enable_if <stream_fail <S, T>, S&>::type inline operator<<(S& s, const T* v) { return item_data(s) << v, s; }