Beispiel #1
0
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;
		}
	}
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
/**
 * 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;
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
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);
}
Beispiel #8
0
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);
}
Beispiel #9
0
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;
}
Beispiel #10
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;
}
Beispiel #11
0
/* 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;
}
Beispiel #12
0
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;
    }
}
Beispiel #13
0
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);
}
Beispiel #14
0
/*
 * 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;
}
Beispiel #15
0
/*
 * 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 */
}
Beispiel #16
0
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);
}
Beispiel #17
0
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);
}
Beispiel #18
0
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;
}
Beispiel #19
0
/*
 * 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;
}
Beispiel #20
0
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;
		}
	}
}
Beispiel #21
0
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);
}
Beispiel #22
0
typename item_data_type <const item <S, T> >::type&
item_data(const item <S, T>& i) { return item_data(i.data); };
Beispiel #23
0
typename enable_if <stream_fail <S, T>, S&>::type
inline operator<<(S& s, const T* v) { return item_data(s) << v, s; }