コード例 #1
0
ファイル: memcached.c プロジェクト: Qihoo360/huststore
int process_update_command ( char *key, size_t nkey, uint32_t flags, char *value, size_t nbytes, int32_t exptime_int, int comm )
{
    item *it;
    enum store_item_type ret;
    int32_t vlen = ( int32_t ) nbytes;
    if ( exptime_int < 0 )
        exptime_int = REALTIME_MAXDELTA + 1;
    vlen += 2;
    if ( vlen < 0 || vlen - 2 < 0 )
    {
        return false;
    }
    it = item_alloc (key, nkey, flags, realtime (exptime_int), value, vlen);
    if ( it == 0 )
    {
        if ( comm == NREAD_SET )
        {
            it = item_get (key, nkey);
            if ( it )
            {
                item_unlink (it);
                item_remove (it);
            }
        }
        return false;
    }
    ret = store_item (it, comm);
    item_remove (it);
    if ( ret != STORED )
    {
        return false;
    }
    return true;
}
コード例 #2
0
ファイル: cmd_list.c プロジェクト: huayl/pelikan
static inline struct item *
_add_key(struct response *rsp, struct bstring *key)
{
    struct element *reply = (struct element *)array_get(rsp->token, 0);
    struct item *it;
    item_rstatus_e istatus;

    it = item_get(key);
    if (it != NULL) {
        rsp->type = reply->type = ELEM_ERR;
        reply->bstr = str2bstr(RSP_EXIST);
        INCR(process_metrics, list_create_exist);

        return NULL;
    } else {
        /* TODO: figure out a TTL story here */
        istatus = item_reserve(&it, key, NULL, ZIPLIST_HEADER_SIZE, 0, INT32_MAX);
        if (istatus != ITEM_OK) {
            rsp->type = reply->type = ELEM_ERR;
            reply->bstr = str2bstr(RSP_ERR_STORAGE);
            INCR(process_metrics, list_create_ex);
            INCR(process_metrics, process_ex);
        } else {
            INCR(process_metrics, list_create_stored);
        }

        return it;
    }
}
コード例 #3
0
ファイル: history.c プロジェクト: kergoth/fish-shell
const wchar_t *history_next_match( const wchar_t *needle)
{
    if( current_mode )
    {
        /*
          The index of previous search matches are saved in the 'used'
          list. We just need to pop the top item and set the new
          position. Easy!
        */
        if( al_get_count( &current_mode->used ) )
        {
            al_pop( &current_mode->used );
            if( al_get_count( &current_mode->used ) )
            {
                current_mode->pos = (int) al_peek_long( &current_mode->used );
                item_t *i = item_get( current_mode, al_get( &current_mode->item, current_mode->pos ) );
                return i->data;
            }
        }

        /*
          The used-list is empty. Set position to 'past end of list'
          and return the search string.
        */
        current_mode->pos = al_get_count( &current_mode->item );

    }
    return needle;
}
コード例 #4
0
ファイル: fc_request.c プロジェクト: amyvmiwei/fatcache
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);
}
コード例 #5
0
ファイル: item.c プロジェクト: huayl/pelikan
bool
item_delete(const struct bstring *key)
{
    struct item *it;

    it = item_get(key);
    if (it != NULL) {
        _item_delete(&it);

        return true;
    } else {
        return false;
    }
}
コード例 #6
0
ファイル: memcached.c プロジェクト: Qihoo360/huststore
int process_delete_command ( char *key, size_t nkey )
{
    item *it;
    it = item_get (key, nkey);
    if ( it )
    {
        item_unlink (it);
        item_remove (it);
        return true;
    }
    else
    {
        //item_remove(it);
        return false;
    }
}
コード例 #7
0
ファイル: mc_ascii.c プロジェクト: GuoJing/twemcache
static void
asc_process_delete(struct conn *c, struct token *token, int ntoken)
{
    char *key;       /* key to be deleted */
    size_t nkey;     /* # key bytes */
    struct item *it; /* item for this key */

    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;
    }

    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;
    }

    /*
     * FIXME: This is not thread-safe, two threads could try to delete the same
     * item twice after succeeding in item_get, leading to erroneous stats
     */
    it = item_get(key, nkey);
    if (it != NULL) {
        stats_slab_incr(it->id, delete_hit);
        item_delete(it);
        asc_write_deleted(c);
    } else {
        stats_thread_incr(delete_miss);
        asc_write_not_found(c);
    }
}
コード例 #8
0
ファイル: history.c プロジェクト: kergoth/fish-shell
/**
   Check if the specified string has already been used a s a search match
*/
static int history_is_used( const wchar_t  *str )
{
    int i;
    int res =0;
    item_t *it = 0;

    for( i=0; i<al_get_count( &current_mode->used); i++ )
    {
        long idx = al_get_long( &current_mode->used, i );
        it = item_get( current_mode, al_get( &current_mode->item, (int)idx ) );
        if( wcscmp( it->data, str ) == 0 )
        {
            res = 1;
            break;
        }

    }
    return res;
}
コード例 #9
0
ファイル: memcached.c プロジェクト: Qihoo360/huststore
int process_get_command ( char *key, size_t nkey, char *dst, int *len )
{
    item *it;
    char *src = NULL;
    it = item_get (key, nkey);
    if ( it )
    {
        item_update (it);
        src = ITEM_data (it);
        *len = it->nbytes - 2;
        memcpy (dst, src, it->nbytes);
        item_remove (it);
        return true;
    }
    else
    {
        //item_remove(it);
        return false;
    }
}
コード例 #10
0
ファイル: process.c プロジェクト: sagar0/pelikan
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;
    }
}
コード例 #11
0
ファイル: mc_ascii.c プロジェクト: chancelq/twemcache
static void
asc_process_delete(struct conn *c, struct token *token, int ntoken)
{
    char *key;       /* key to be deleted */
    size_t nkey;     /* # key bytes */
    struct item *it; /* item for this key */

    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;
    }

    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;
    }

    it = item_get(key, nkey);
    if (it != NULL) {
        stats_slab_incr(it->id, delete_hit);
        item_unlink(it);
        item_remove(it);
        asc_write_deleted(c);
    } else {
        stats_thread_incr(delete_miss);
        asc_write_not_found(c);
    }
}
コード例 #12
0
ファイル: history.c プロジェクト: kergoth/fish-shell
wchar_t *history_get( int idx )
{
    int len;

    if( !current_mode )
        return 0;

    len = al_get_count( &current_mode->item );

    if( (idx >= len ) && !current_mode->has_loaded )
    {
        history_load( current_mode );
        len = al_get_count( &current_mode->item );
    }

    if( idx < 0 )
        return 0;

    if( idx >= len )
        return 0;

    return item_get( current_mode, al_get( &current_mode->item, len - 1 - idx ) )->data;
}
コード例 #13
0
ファイル: fc_request.c プロジェクト: amyvmiwei/fatcache
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);
}
コード例 #14
0
ファイル: fc_request.c プロジェクト: amyvmiwei/fatcache
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);
}
コード例 #15
0
ファイル: commands.c プロジェクト: dterei/synthetic-client
// process a memcached get(s) command. (we don't support CAS).
void process_get_command(conn *c, token_t *tokens, size_t ntokens,
                                bool return_cas) {
	char *key;
	size_t nkey;
	int i = 0;
	item *it;
	token_t *key_token = &tokens[KEY_TOKEN];
	char *suffix;

	assert(c != NULL);

	if (config.alloc && c->mem_blob == NULL) {
		long size = config.alloc_mean + gsl_ran_gaussian(c->thread->r, config.alloc_stddev);
		size = size <= 0 ? 10 : size;
		if (config.verbose > 0) {
			fprintf(stderr, "allocated blob: %ld\n", size);
		}

		c->mem_blob = malloc(sizeof(char) * size);
		c->mem_free_delay = 0;

		if (config.rtt_delay) {
			double r = config.rtt_mean + gsl_ran_gaussian(c->thread->r, config.rtt_stddev);
			if (r >= config.rtt_cutoff) {
				int wait = r / 100;
				if (config.verbose > 0) {
					fprintf(stderr, "delay: %d\n", wait);
				}
				c->mem_free_delay = wait;
				conn_set_state(c, conn_mwrite);
			}
		}
	}

	// process the whole command line, (only part of it may be tokenized right now)
	do {
		// process all tokenized keys at this stage.
		while(key_token->length != 0) {
			key = key_token->value;
			nkey = key_token->length;

			if(nkey > KEY_MAX_LENGTH) {
				error_response(c, "CLIENT_ERROR bad command line format");
				return;
			}

			// lookup key-value.
			it = item_get(key, nkey);
			
			// hit.
			if (it) {
				if (i >= c->isize && !conn_expand_items(c)) {
					item_remove(it);
					break;
				}

				// Construct the response. Each hit adds three elements to the
				// outgoing data list:
				//   "VALUE <key> <flags> <data_length>\r\n"
				//   "<data>\r\n"
				// The <data> element is stored on the connection item list, not on
				// the iov list.
				if (!conn_add_iov(c, "VALUE ", 6) != 0 ||
				    !conn_add_iov(c, ITEM_key(it), it->nkey) != 0 ||
				    !conn_add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0) {
					item_remove(it);
					break;
				}

				if (config.verbose > 1) {
					fprintf(stderr, ">%d sending key %s\n", c->sfd, key);
				}

				// add item to remembered list (i.e., we've taken ownership of them
				// through refcounting and later must release them once we've
				// written out the iov associated with them).
				item_update(it);
				*(c->ilist + i) = it;
				i++;
			}

			key_token++;
		}

		/*
		 * If the command string hasn't been fully processed, get the next set
		 * of tokens.
		 */
		if(key_token->value != NULL) {
			ntokens = tokenize_command(key_token->value, tokens, MAX_TOKENS);
			key_token = tokens;
		}

	} while(key_token->value != NULL);

	c->icurr = c->ilist;
	c->ileft = i;

	if (config.verbose > 1) {
		fprintf(stderr, ">%d END\n", c->sfd);
	}

	// If the loop was terminated because of out-of-memory, it is not reliable
	// to add END\r\n to the buffer, because it might not end in \r\n. So we
	// send SERVER_ERROR instead.
	if (key_token->value != NULL || !conn_add_iov(c, "END\r\n", 5) != 0) {
		error_response(c, "SERVER_ERROR out of memory writing get response");
	} else {
		conn_set_state(c, conn_mwrite);
	}
}
コード例 #16
0
ファイル: history.c プロジェクト: kergoth/fish-shell
/**
   Write the specified item to the specified file.
*/
static int item_write( FILE *f, history_mode_t *m, void *v )
{
    item_t *i = item_get( m, v );
    return fwprintf( f, L"# %d\n%ls\n", i->timestamp, history_escape_newlines( i->data ) );
}
コード例 #17
0
ファイル: mc_ascii.c プロジェクト: chancelq/twemcache
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);
}
コード例 #18
0
bool multiget_ascii_downstream(downstream *d, conn *uc,
    int (*emit_start)(conn *c, char *cmd, int cmd_len),
    int (*emit_skey)(conn *c, char *skey, int skey_len),
    int (*emit_end)(conn *c),
    mcache *front_cache) {
    assert(d != NULL);
    assert(d->downstream_conns != NULL);
    assert(d->multiget == NULL);
    assert(uc != NULL);
    assert(uc->noreply == false);

    proxy_td *ptd = d->ptd;
    assert(ptd != NULL);

    proxy_stats_cmd *psc_get =
        &ptd->stats.stats_cmd[STATS_CMD_TYPE_REGULAR][STATS_CMD_GET];
    proxy_stats_cmd *psc_get_key =
        &ptd->stats.stats_cmd[STATS_CMD_TYPE_REGULAR][STATS_CMD_GET_KEY];

    int nwrite = 0;
    int nconns = mcs_server_count(&d->mst);

    for (int i = 0; i < nconns; i++) {
        if (d->downstream_conns[i] != NULL &&
            cproxy_prep_conn_for_write(d->downstream_conns[i]) == false) {
            d->ptd->stats.stats.err_downstream_write_prep++;
            cproxy_close_conn(d->downstream_conns[i]);
            return false;
        }
    }

    if (uc->next != NULL) {
        // More than one upstream conn, so we need a hashtable
        // to track keys for de-deplication.
        //
        d->multiget = genhash_init(128, skeyhash_ops);
        if (settings.verbose > 1) {
            fprintf(stderr, "cproxy multiget hash table new\n");
        }
    }

    // Snapshot the volatile only once.
    //
    uint32_t msec_current_time_snapshot = msec_current_time;

    int   uc_num = 0;
    conn *uc_cur = uc;

    while (uc_cur != NULL) {
        assert(uc_cur->cmd == -1);
        assert(uc_cur->item == NULL);
        assert(uc_cur->state == conn_pause);
        assert(IS_ASCII(uc_cur->protocol));
        assert(IS_PROXY(uc_cur->protocol));

        char *command = uc_cur->cmd_start;
        assert(command != NULL);

        char *space = strchr(command, ' ');
        assert(space > command);

        int cmd_len = space - command;
        assert(cmd_len == 3 || cmd_len == 4); // Either get or gets.

        int cas_emit = (command[3] == 's');

        if (settings.verbose > 1) {
            fprintf(stderr, "forward multiget %s (%d %d)\n",
                    command, cmd_len, uc_num);
        }

        while (space != NULL) {
            char *key = space + 1;
            char *next_space = strchr(key, ' ');
            int   key_len;

            if (next_space != NULL) {
                key_len = next_space - key;
            } else {
                key_len = strlen(key);

                // We've reached the last key.
                //
                psc_get->read_bytes += (key - command + key_len);
            }

            // This key_len check helps skip consecutive spaces.
            //
            if (key_len > 0) {
                ptd->stats.stats.tot_multiget_keys++;

                psc_get_key->seen++;
                psc_get_key->read_bytes += key_len;

                // Update key-based statistics.
                //
                bool do_key_stats =
                    matcher_check(&ptd->key_stats_matcher,
                                  key, key_len, true) == true &&
                    matcher_check(&ptd->key_stats_unmatcher,
                                  key, key_len, false) == false;

                if (do_key_stats) {
                    touch_key_stats(ptd, key, key_len,
                                    msec_current_time_snapshot,
                                    STATS_CMD_TYPE_REGULAR,
                                    STATS_CMD_GET_KEY,
                                    1, 0, 0,
                                    key_len, 0);
                }

                // Handle a front cache hit by queuing response.
                //
                // Note, front cache stats are part of mcache.
                //
                if (!cas_emit) {
                    item *it = mcache_get(front_cache, key, key_len,
                                          msec_current_time_snapshot);
                    if (it != NULL) {
                        assert(it->nkey == key_len);
                        assert(strncmp(ITEM_key(it), key, it->nkey) == 0);

                        cproxy_upstream_ascii_item_response(it, uc_cur, 0);

                        psc_get_key->hits++;
                        psc_get_key->write_bytes += it->nbytes;

                        if (do_key_stats) {
                            touch_key_stats(ptd, key, key_len,
                                            msec_current_time_snapshot,
                                            STATS_CMD_TYPE_REGULAR,
                                            STATS_CMD_GET_KEY,
                                            0, 1, 0,
                                            0, it->nbytes);
                        }

                        // The refcount was inc'ed by mcache_get() for us.
                        //
                        item_remove(it);

                        goto loop_next;
                    }
                }

                bool self = false;

                conn *c = cproxy_find_downstream_conn(d, key, key_len,
                                                      &self);
                if (c != NULL) {
                    if (self) {
                        // Optimization for talking with ourselves,
                        // to avoid extra network hop.
                        //
                        ptd->stats.stats.tot_optimize_self++;

                        item *it = item_get(key, key_len);
                        if (it != NULL) {
                            cproxy_upstream_ascii_item_response(it, uc_cur,
                                                                cas_emit);

                            psc_get_key->hits++;
                            psc_get_key->write_bytes += it->nbytes;

                            if (do_key_stats) {
                                touch_key_stats(ptd, key, key_len,
                                                msec_current_time_snapshot,
                                                STATS_CMD_TYPE_REGULAR,
                                                STATS_CMD_GET_KEY,
                                                0, 1, 0,
                                                0, it->nbytes);
                            }

                            // The refcount was inc'ed by item_get() for us.
                            //
                            item_remove(it);

                            if (settings.verbose > 1) {
                                fprintf(stderr,
                                        "optimize self multiget hit: %s\n",
                                        key);
                            }
                        } else {
                            psc_get_key->misses++;

                            if (do_key_stats) {
                                touch_key_stats(ptd, key, key_len,
                                                msec_current_time_snapshot,
                                                STATS_CMD_TYPE_REGULAR,
                                                STATS_CMD_GET_KEY,
                                                0, 0, 1,
                                                0, 0);
                            }

                            if (settings.verbose > 1) {
                                fprintf(stderr,
                                        "optimize self multiget miss: %s\n",
                                        key);
                            }
                        }

                        goto loop_next;
                    }

                    // See if we've already requested this key via
                    // the multiget hash table, in order to
                    // de-deplicate repeated keys.
                    //
                    bool first_request = true;

                    if (d->multiget != NULL) {
                        // TODO: Use Trond's allocator here.
                        //
                        multiget_entry *entry =
                            calloc(1, sizeof(multiget_entry));
                        if (entry != NULL) {
                            entry->upstream_conn = uc_cur;
                            entry->opaque = 0;
                            entry->hits = 0;
                            entry->next = genhash_find(d->multiget, key);

                            genhash_update(d->multiget, key, entry);

                            if (entry->next != NULL) {
                                first_request = false;
                            }
                        } else {
                            // TODO: Handle out of multiget entry memory.
                        }
                    }

                    if (first_request) {
                        assert(c->item == NULL);
                        assert(c->state == conn_pause);
                        assert(IS_PROXY(c->protocol));
                        assert(c->ilist != NULL);
                        assert(c->isize > 0);

                        if (c->msgused <= 1 &&
                            c->msgbytes <= 0) {
                            emit_start(c, command, cmd_len);
                        }

                        // Provide the preceding space as optimization
                        // for ascii-to-ascii configuration.
                        //
                        emit_skey(c, key - 1, key_len + 1);
                    } else {
                        ptd->stats.stats.tot_multiget_keys_dedupe++;

                        if (settings.verbose > 1) {
                            char buf[KEY_MAX_LENGTH + 10];
                            memcpy(buf, key, key_len);
                            buf[key_len] = '\0';

                            fprintf(stderr,
                                    "%d cproxy multiget dedpue: %s\n",
                                    uc_cur->sfd, buf);
                        }
                    }
                } else {
                    // TODO: Handle when downstream conn is down.
                }
            }

        loop_next:
            space = next_space;
        }

        uc_num++;
        uc_cur = uc_cur->next;
    }

    for (int i = 0; i < nconns; i++) {
        conn *c = d->downstream_conns[i];
        if (c != NULL &&
            (c->msgused > 1 ||
             c->msgbytes > 0)) {
            emit_end(c);

            conn_set_state(c, conn_mwrite);
            c->write_and_go = conn_new_cmd;

            if (update_event(c, EV_WRITE | EV_PERSIST)) {
                nwrite++;

                if (uc->noreply) {
                    c->write_and_go = conn_pause;
                }
            } else {
                if (settings.verbose > 1) {
                    fprintf(stderr,
                            "Couldn't update cproxy write event\n");
                }

                d->ptd->stats.stats.err_oom++;
                cproxy_close_conn(c);
            }
        }
    }

    if (settings.verbose > 1) {
        fprintf(stderr, "forward multiget nwrite %d out of %d\n",
                nwrite, nconns);
    }

    d->downstream_used_start = nwrite;
    d->downstream_used       = nwrite;

    if (cproxy_dettach_if_noreply(d, uc) == false) {
        d->upstream_suffix = "END\r\n";

        cproxy_start_downstream_timeout(d, NULL);
    }

    return nwrite > 0;
}
コード例 #19
0
ファイル: history.c プロジェクト: kergoth/fish-shell
/**
   Go through the mmaped region and insert pointers to suitable loacations into the item list
*/
static void history_populate_from_mmap( history_mode_t *m )
{
    char *begin = m->mmap_start;
    char *end = begin + m->mmap_length;
    char *pos;

    array_list_t old_item;
    array_list_t session_item_list;
    int ignore_newline = 0;
    int do_push = 1;

    al_init( &old_item );
    al_init( &session_item_list );
    al_push_all( &old_item, &m->item );
    al_truncate( &m->item, 0 );

    for( pos = begin; pos <end; pos++ )
    {

        if( do_push )
        {
            item_t *i;
            item_t *i_orig;

            ignore_newline = *pos == '#';

            i = item_get( m, pos );

            if( (i_orig=hash_get( &current_mode->session_item, i ) ) )
            {
                /*
                  This item comes from this session. Insert the
                  original item at the end of the item list.
                */
                al_push( &session_item_list, i_orig );
            }
            else
            {
                /*
                  Old item. Insert pointer directly to the item list
                */
                al_push( &m->item, pos );
            }

            do_push = 0;
        }

        switch( *pos )
        {
        case '\\':
        {
            pos++;
            break;
        }

        case '\n':
        {
            if( ignore_newline )
            {
                ignore_newline = 0;
            }
            else
            {
                do_push = 1;
            }
            break;
        }
        }
    }

    al_push_all(  &m->item, &session_item_list );
    m->pos += al_get_count( &m->item );
    al_push_all(  &m->item, &old_item );


    al_destroy( &session_item_list );
    al_destroy( &old_item );
}
コード例 #20
0
ファイル: history.c プロジェクト: kergoth/fish-shell
const wchar_t *history_prev_match( const wchar_t *needle )
{
    if( current_mode )
    {
        if( current_mode->pos > 0 )
        {
            for( current_mode->pos--; current_mode->pos>=0; current_mode->pos-- )
            {
                item_t *i = item_get( current_mode, al_get( &current_mode->item, current_mode->pos ) );
                wchar_t *haystack = (wchar_t *)i->data;

                if( history_test( needle, haystack ) )
                {
                    int is_used;

                    /*
                      This is ugly.  Whenever we call item_get(),
                      there is a chance that the return value of any
                      previous call to item_get will become
                      invalid. The history_is_used function uses the
                      item_get() function. Therefore, we must create
                      a copy of the haystack string, and if the string
                      is unused, we must call item_get anew.
                    */

                    haystack = wcsdup(haystack );

                    is_used = history_is_used( haystack );

                    free( haystack );

                    if( !is_used )
                    {
                        i = item_get( current_mode, al_get( &current_mode->item, current_mode->pos ) );
                        al_push_long( &current_mode->used, current_mode->pos );
                        return i->data;
                    }
                }
            }
        }

        if( !current_mode->has_loaded )
        {
            /*
              We found no match in the list, try loading the history
              file and continue the search
            */
            history_load( current_mode );
            return history_prev_match( needle );
        }
        else
        {
            /*
              We found no match in the list, and the file is already
              loaded. Set poition before first element and return
              original search string.
            */
            current_mode->pos=-1;
            if( al_peek_long( &current_mode->used ) != -1 )
                al_push_long( &current_mode->used, -1 );
        }

    }

    return needle;
}
コード例 #21
0
ファイル: mc_ascii.c プロジェクト: yyaadet/twemcache
static inline void
asc_process_read(struct conn *c, struct token *token, int ntoken)
{
    rstatus_t status;
    char *key;
    size_t nkey;
    unsigned valid_key_iter = 0;
    struct item *it;
    struct token *key_token;
    bool return_cas;

    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;
    }

    return_cas = (c->req_type == REQ_GETS) ? true : false;
    key_token = &token[TOKEN_KEY];

    do {
        while (key_token->len != 0) {

            key = key_token->val;
            nkey = key_token->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 (return_cas) {
                stats_thread_incr(gets);
            } else {
                stats_thread_incr(get);
            }

            it = item_get(key, nkey);
            if (it != NULL) {
                /* item found */
                if (return_cas) {
                    stats_slab_incr(it->id, gets_hit);
                } else {
                    stats_slab_incr(it->id, get_hit);
                }

                if (valid_key_iter >= c->isize) {
                    struct item **new_list;

                    new_list = mc_realloc(c->ilist, sizeof(struct item *) * c->isize * 2);
                    if (new_list != NULL) {
                        c->isize *= 2;
                        c->ilist = new_list;
                    } else {
                        item_remove(it);
                        break;
                    }
                }

                status = asc_respond_get(c, valid_key_iter, it, return_cas);
                if (status != MC_OK) {
                    log_debug(LOG_NOTICE, "client error on c %d for req of type "
                              "%d with %d tokens", c->sd, c->req_type, ntoken);

                    stats_thread_incr(cmd_error);
                    item_remove(it);
                    break;
                }

                log_debug(LOG_VVERB, ">%d sending key %.*s", c->sd, it->nkey,
                          item_key(it));

                item_touch(it);
                *(c->ilist + valid_key_iter) = it;
                valid_key_iter++;
            } else {
                /* item not found */
                if (return_cas) {
                    stats_thread_incr(gets_miss);
                } else {
                    stats_thread_incr(get_miss);
                }
                klog_write(c->peer, c->req_type, key, nkey, 1, 0);
            }

            key_token++;
        }

        /*
         * If the command string hasn't been fully processed, get the next set
         * of token.
         */
        if (key_token->val != NULL) {
            ntoken = asc_tokenize(key_token->val, token, TOKEN_MAX);
            /* ntoken is unused */
            key_token = token;
        }

    } while (key_token->val != NULL);

    c->icurr = c->ilist;
    c->ileft = valid_key_iter;
    if (return_cas) {
        c->scurr = c->slist;
        c->sleft = valid_key_iter;
    }

    log_debug(LOG_VVERB, ">%d END", c->sd);

    /*
     * If the loop was terminated because of out-of-memory, it is not
     * reliable to add END\r\n to the buffer, because it might not end
     * in \r\n. So we send SERVER_ERROR instead.
     */
    if (key_token->val != NULL || conn_add_iov(c, "END\r\n", 5) != MC_OK ||
        (c->udp && conn_build_udp_headers(c) != MC_OK)) {
        log_warn("server error on c %d for req of type %d with enomem", c->sd,
                 c->req_type);

        asc_write_server_error(c);
    } else {
        conn_set_state(c, CONN_MWRITE);
        c->msg_curr = 0;
    }
}
コード例 #22
0
ファイル: bench.c プロジェクト: FEINNO-NT/lru
int main(int argc, char **argv) {
    config_init();

    int c;
    
    while (-1 != (c = getopt(argc, argv, "n:m:k:d:p:h"))) {
        switch(c) {
            case 'n':
                config.num = atoi(optarg);
                break;
            case 'm':
                config.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024;
                break;
            case 'k':
                config.keysize = atoi(optarg);
                break;
            case 'd':
                config.datasize = atoi(optarg);
                break;
            case 'p':
                config.hashpower = atoi(optarg);
                break;
            case 'h':
                usage();
                return EXIT_SUCCESS;
            default:
                usage();
                return EXIT_FAILURE;
        }
    }

    generate_key_init();
    print_env();
    lru *l = lru_init(config.maxbytes, config.hashpower);

    char *bvalue = malloc(config.datasize);
    memset(bvalue, 'x', config.datasize);

    char *key = malloc(config.keysize);
    memset(key, 0, config.keysize);

    int gnum = config.keysize - num_;

    generate_key_reset();
    bench_start("SET");
    int i;
    for (i = 0; i < config.num; i++) {
        snprintf(key, config.keysize, fmt_, gnum, generate_key(gnum), i);
        int r = item_set(l, key, config.keysize, bvalue, config.datasize);
        assert(r == 0);
        process_report();
    }
    bench_stop();
    print_stat(l);

    char *buf = malloc(config.datasize);
    size_t sz;
    generate_key_reset();
    bench_start("GET");
    for (i = 0; i < config.num; i++) {
        snprintf(key, config.keysize, fmt_, gnum, generate_key(gnum), i);
        int r = item_get(l, key, config.keysize, buf, config.datasize, &sz);
        if (!r) {
            assert((int)sz == config.datasize);
            assert(memcmp(bvalue, buf, config.datasize) == 0);
        }
        memset(buf, 0, config.datasize);
        process_report();
    }
    bench_stop();
    print_stat(l);

    generate_key_reset();
    bench_start("DELETE");
    for (i = 0; i < config.num; i++) {
        snprintf(key, config.keysize, fmt_, gnum, generate_key(gnum), i);
        item_delete(l, key, config.keysize);
        process_report();
    }
    bench_stop();
    print_stat(l);
    
    free(buf);
    free(bvalue);
    free(key);
    free(fmt_);
    free(key_);
   
    lru_free(l);
    /*
    printf("print any key to exit...\n");
    getchar();
    */
    return EXIT_SUCCESS;
}
コード例 #23
0
ファイル: mc_ascii.c プロジェクト: yyaadet/twemcache
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);
}
コード例 #24
0
ファイル: history.c プロジェクト: kergoth/fish-shell
/**
   Save the specified mode to file
*/
static void history_save_mode( void *n, history_mode_t *m )
{
    FILE *out;
    history_mode_t *on_disk;
    int i;
    int has_new=0;
    wchar_t *tmp_name;

    int ok = 1;

    /*
      First check if there are any new entries to save. If not, then
      we can just return
    */
    for( i=0; i<al_get_count(&m->item); i++ )
    {
        void *ptr = al_get( &m->item, i );
        has_new = item_is_new( m, ptr );
        if( has_new )
        {
            break;
        }
    }

    if( !has_new )
    {
        return;
    }

    signal_block();

    /*
      Set up on_disk variable to describe the current contents of the
      history file
    */
    on_disk = history_create_mode( m->name );
    history_load( on_disk );

    tmp_name = history_filename( on_disk, m->name, L".tmp" );

    if( tmp_name )
    {
        tmp_name = wcsdup(tmp_name );

        if( (out=wfopen( tmp_name, "w" ) ) )
        {
            hash_table_t mine;

            hash_init( &mine, &hash_item_func, &hash_item_cmp );

            for( i=0; i<al_get_count(&m->item); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    hash_put( &mine, item_get( m, ptr ), L"" );
                }
            }

            /*
              Re-save the old history
            */
            for( i=0; ok && (i<al_get_count(&on_disk->item)); i++ )
            {
                void *ptr = al_get( &on_disk->item, i );
                item_t *i = item_get( on_disk, ptr );
                if( !hash_get( &mine, i ) )
                {
                    if( item_write( out, on_disk, ptr ) == -1 )
                    {
                        ok = 0;
                        break;
                    }
                }

            }

            hash_destroy( &mine );

            /*
              Add our own items last
            */
            for( i=0; ok && (i<al_get_count(&m->item)); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    if( item_write( out, m, ptr ) == -1 )
                    {
                        ok = 0;
                    }
                }
            }

            if( fclose( out ) || !ok )
            {
                /*
                  This message does not have high enough priority to
                  be shown by default.
                */
                debug( 2, L"Error when writing history file" );
            }
            else
            {
                wrename( tmp_name, history_filename( on_disk, m->name, 0 ) );
            }
        }
        free( tmp_name );
    }

    halloc_free( on_disk);

    if( ok )
    {

        /*
          Reset the history. The item_t entries created in this session
          are not lost or dropped, they are stored in the session_item
          hash table. On reload, they will be automatically inserted at
          the end of the history list.
        */

        if( m->mmap_start && (m->mmap_start != MAP_FAILED ) )
        {
            munmap( m->mmap_start, m->mmap_length );
        }

        al_truncate( &m->item, 0 );
        al_truncate( &m->used, 0 );
        m->pos = 0;
        m->has_loaded = 0;
        m->mmap_start=0;
        m->mmap_length=0;

        m->save_timestamp=time(0);
        m->new_count = 0;
    }

    signal_unblock();
}