예제 #1
0
static struct item* _item_alloc(uint8_t id, char *key, uint16_t nkey, int exptime, char *value, uint32_t nbyte) {
    struct item *it;
    struct item *uit;
    assert(id >= SLABCLASS_MIN_ID && id <= SLABCLASS_MAX_ID);
    it = item_get_from_lruq(id);
    if (it != NULL && item_expired(it)) {
        item_reuse(it);
        goto done;
    }
    uit = (settings.evict_opt & EVICT_LRU)? it : NULL;
    it = slab_get_item(id);
    if (it != NULL) {
        goto done;
    }
    if (uit != NULL) {
        it = uit;
        item_reuse(it);
        goto done;
    }
    return NULL;
done:
    assert(it->id == id);
    assert(!item_is_linked(it));
    assert(!item_is_slabbed(it));
    assert(it->offset != 0);
    assert(it->refcount == 0);
    it->flags = 0;
    it->nbyte = nbyte;
    it->exptime = exptime + time_now();
    it->nkey = nkey;
    memcpy(item_key(it), key, nkey);
    memcpy(item_key(it) + nkey, value, nbyte);
    return it;
}
예제 #2
0
파일: item.c 프로젝트: huayl/pelikan
static inline void
_copy_key_item(struct item *nit, struct item *oit)
{
    nit->olen = oit->olen;
    cc_memcpy(item_key(nit), item_key(oit), oit->klen);
    nit->klen = oit->klen;
}
예제 #3
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;
}
예제 #4
0
파일: hashtable.c 프로젝트: kevyang/pelikan
void
hashtable_put(struct item *it, struct hash_table *ht)
{
    struct item_slh *bucket;

    ASSERT(hashtable_get(item_key(it), it->klen, ht) == NULL);

    bucket = _get_bucket(item_key(it), it->klen, ht);
    SLIST_INSERT_HEAD(bucket, it, i_sle);

    ++(ht->nhash_item);
}
예제 #5
0
파일: hashtable.c 프로젝트: kevyang/pelikan
void
hashtable_delete(const char *key, uint32_t klen, struct hash_table *ht)
{
    struct item_slh *bucket;
    struct item *it, *prev;

    ASSERT(hashtable_get(key, klen, ht) != NULL);

    bucket = _get_bucket(key, klen, ht);
    for (prev = NULL, it = SLIST_FIRST(bucket); it != NULL;
        prev = it, it = SLIST_NEXT(it, i_sle)) {
        /* iterate through bucket to find item to be removed */
        if ((klen == it->klen) && cc_memcmp(key, item_key(it), klen) == 0) {
            /* found item */
            break;
        }
    }

    if (prev == NULL) {
        SLIST_REMOVE_HEAD(bucket, i_sle);
    } else {
        SLIST_REMOVE_AFTER(prev, i_sle);
    }

    --(ht->nhash_item);
}
예제 #6
0
void item_reuse(struct item *it) {
	assert(pthread_mutex_trylock(&cache_lock) != 0);
	assert(it->magic == ITEM_MAGIC);
	assert(!item_is_slabbed(it));
	assert(item_is_linked(it));
	assert(it->refcount == 0);
    it->flags &= ~ITEM_LINKED;
    assoc_delete(item_key(it), it->nkey);
    item_unlink_q(it);
}
예제 #7
0
static void _item_unlink(struct item *it) {
	assert(it->magic == ITEM_MAGIC);
	assert(item_is_linked(it));
    if (item_is_linked(it)) {
        it->flags &= ~ITEM_LINKED;
        assoc_delete(item_key(it), it->nkey);
        item_unlink_q(it);
        if (it->refcount == 0) {
            item_free(it);
        }
    }
}
예제 #8
0
파일: item.c 프로젝트: huayl/pelikan
/* 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;
}
예제 #9
0
파일: item.c 프로젝트: huayl/pelikan
/*
 * Unlinks an item from the hash table.
 */
static void
_item_unlink(struct item *it)
{
    ASSERT(it->magic == ITEM_MAGIC);

    log_verb("unlink it %p of id %"PRIu8" at offset %"PRIu32, it, it->id,
            it->offset);

    if (it->is_linked) {
        it->is_linked = 0;
        hashtable_delete(item_key(it), it->klen, hash_table);
    }
    DECR(slab_metrics, item_linked_curr);
    INCR(slab_metrics, item_unlink);
    DECR_N(slab_metrics, item_keyval_byte, it->klen + it->vlen);
    DECR_N(slab_metrics, item_val_byte, it->vlen);
    PERSLAB_DECR_N(it->id, item_keyval_byte, it->klen + it->vlen);
    PERSLAB_DECR_N(it->id, item_val_byte, it->vlen);
}
예제 #10
0
파일: hashtable.c 프로젝트: kevyang/pelikan
struct item *
hashtable_get(const char *key, uint32_t klen, struct hash_table *ht)
{
    struct item_slh *bucket;
    struct item *it;

    ASSERT(key != NULL);
    ASSERT(klen != 0);

    bucket = _get_bucket(key, klen, ht);
    /* iterate through bucket looking for item */
    for (it = SLIST_FIRST(bucket); it != NULL; it = SLIST_NEXT(it, i_sle)) {
        if ((klen == it->klen) && cc_memcmp(key, item_key(it), klen) == 0) {
            /* found item */
            return it;
        }
    }

    return NULL;
}
예제 #11
0
static void *
assoc_maintenance_thread(void *arg)
{
    uint32_t i, hv;
    struct item_slh *old_bucket, *new_bucket;
    struct item *it, *next;

    while (run_maintenance_thread) {
        /*
         * Lock the cache, and bulk move multiple buckets to the new
         * hash table
         */
        pthread_mutex_lock(&cache_lock);

        for (i = 0; i < nhash_move_size && expanding == 1; i++) {

            old_bucket = &old_hashtable[expand_bucket];

            SLIST_FOREACH_SAFE(it, old_bucket, h_sle, next) {
                hv = hash(item_key(it), it->nkey, 0);
                new_bucket = &primary_hashtable[hv & HASHMASK(hash_power)];
                SLIST_REMOVE(old_bucket, it, item, h_sle);
                SLIST_INSERT_HEAD(new_bucket, it, h_sle);
            }

            expand_bucket++;
            if (expand_bucket == HASHSIZE(hash_power - 1)) {
                expanding = 0;
                mc_free(old_hashtable);
                nbyte_old = 0;
            }
        }

        if (expanding == 0) {
            /* we are done expanding, just wait for the next invocation */
            pthread_cond_wait(&maintenance_cond, &cache_lock);
        }

        pthread_mutex_unlock(&cache_lock);
    }
예제 #12
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Evict a slab by evicting all the items within it. This means that the
 * items that are carved out of the slab must either be deleted from their
 * a) hash + lru Q, or b) free Q. The candidate slab itself must also be
 * delinked from its respective slab pool so that it is available for reuse.
 *
 * Eviction complexity is O(#items/slab).
 */
static void
_slab_evict_one(struct slab *slab)
{
    struct slabclass *p;
    struct item *it;
    uint32_t i;

    p = &slabclass[slab->id];

    INCR(slab_metrics, slab_evict);

    /* candidate slab is also the current slab */
    if (p->next_item_in_slab != NULL && slab == item_to_slab(p->next_item_in_slab)) {
        p->nfree_item = 0;
        p->next_item_in_slab = NULL;
    }

    /* delete slab items either from hash or free Q */
    for (i = 0; i < p->nitem; i++) {
        it = _slab_to_item(slab, i, p->size);

        if (it->is_linked) {
            it->is_linked = 0;
            hashtable_delete(item_key(it), it->klen, hash_table);
        } else if (it->in_freeq) {
            ASSERT(slab == item_to_slab(it));
            ASSERT(!SLIST_EMPTY(&p->free_itemq));
            ASSERT(p->nfree_itemq > 0);

            it->in_freeq = 0;
            p->nfree_itemq--;
            SLIST_REMOVE(&p->free_itemq, it, item, i_sle);
        }
    }

    /* unlink the slab from its class */
    _slab_lruq_remove(slab);
}
예제 #13
0
파일: fs.c 프로젝트: jdbeutel/ics612-babyfs
/* gets the inode of a directory entry, or 0 if errno.
 * (inode 0 is the root dir, which is not an entry in any dir)
 */
PUBLIC uint32_t get_dir_ent_inode(struct fs_info *fsi, uint32_t dir_inode,
									char *name) {
	struct path p;
	struct key key;
	struct dir_ent_metadata *demd;
	int ret;

	set_dir_ent_key(dir_inode, name, &key);
	ret = search_slot(&fsi->fs_root, &key, &p, 0);
	if (ret == KEY_NOT_FOUND) {
		free_path(&p);	/* only for search_slot(), not step_to_next_slot() */
	}
	while (TRUE) {
		if (ret == KEY_NOT_FOUND) {
			errno = ENOENT;
		}
		if (ret < 0) {
			errno = -ret;
		}
		if (ret != KEY_FOUND) {
			return 0;	/* failure, with errno */
		}
		demd = (struct dir_ent_metadata *) metadata_for(&p);
		if (!strcmp(name, demd->name)) {	/* name matches */
			ret = demd->inode;
			free_path(&p);
			return ret;
		}
		ret = step_to_next_slot(&p);
		if (ret == KEY_FOUND && compare_keys(&key, item_key(&p))) {
			errno = ENOENT;
			free_path(&p);
			return 0;	/* failure, with errno */
		}
	}
}
예제 #14
0
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;
    }
}
예제 #15
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;
}
예제 #16
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;
}
예제 #17
0
파일: fc_slab.c 프로젝트: AKdroid/fatcache
void
slab_put_item(struct item *it)
{
    log_debug(LOG_INFO, "put it '%.*s' at offset %"PRIu32" with cid %"PRIu8,
              it->nkey, item_key(it), it->offset, it->cid);
}