예제 #1
0
파일: process.c 프로젝트: sagar0/pelikan
static bool
_get_key(struct response *rsp, struct bstring *key)
{
    struct item *it;
    struct val val;

    it = cuckoo_get(key);
    if (it != NULL) {
        rsp->type = RSP_VALUE;
        rsp->key = *key;
        rsp->flag = item_flag(it);
        rsp->vcas = item_cas(it);
        item_val(&val, it);
        if (val.type == VAL_TYPE_INT) {
            rsp->num = 1;
            rsp->vint = val.vint;
        } else {
            rsp->vstr = val.vstr;
        }

        log_verb("found key at %p, location %p", key, it);
        return true;
    } else {
        log_verb("key at %p not found", key);
        return false;
    }
}
예제 #2
0
파일: server.c 프로젝트: sagar0/pelikan
static void
_server_event(void *arg, uint32_t events)
{
    struct buf_sock *s = arg;

    log_verb("server event %06"PRIX32" on buf_sock %p", events, s);

    if (events & EVENT_ERR) {
        INCR(server_metrics, server_event_error);
        _server_close(s);

        return;
    }

    if (events & EVENT_READ) {
        log_verb("processing server read event on buf_sock %p", s);

        INCR(server_metrics, server_event_read);
        _server_event_read(s);
    }

    if (events & EVENT_WRITE) {
        /* the only server write event is write on pipe */

        log_verb("processing server write event");
        _server_pipe_write();

        INCR(server_metrics, server_event_write);
    }
}
예제 #3
0
파일: item.c 프로젝트: huayl/pelikan
/**
 * 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;
}
예제 #4
0
파일: item.c 프로젝트: huayl/pelikan
/*
 * Allocate an item. We allocate an item by consuming the next free item
 * from slab of the item's slab class.
 *
 * On success we return the pointer to the allocated item.
 */
static item_rstatus_e
_item_alloc(struct item **it_p, uint8_t klen, uint32_t vlen, uint8_t olen)
{
    uint8_t id = slab_id(item_ntotal(klen, vlen, olen));
    struct item *it;

    log_verb("allocate item with klen %u vlen %u", klen, vlen);

    *it_p = NULL;
    if (id == SLABCLASS_INVALID_ID) {
        return ITEM_EOVERSIZED;
    }

    it = slab_get_item(id);
    *it_p = it;
    if (it != NULL) {
        _item_reset(it);
        slab_ref(item_to_slab(it)); /* slab to be deref'ed in _item_link */
        INCR(slab_metrics, item_curr);
        INCR(slab_metrics, item_alloc);
        PERSLAB_INCR(id, item_curr);

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

        return ITEM_OK;
    } else {
        INCR(slab_metrics, item_alloc_ex);
        log_warn("server error on allocating item in slab %"PRIu8, id);

        return ITEM_ENOMEM;
    }
}
예제 #5
0
파일: nc_connection.c 프로젝트: idning/ndb
/*
 * TODO: return size_t , but actually we return NC_ERROR
 * */
static ssize_t
conn_recv_buf(struct conn *conn, void *buf, size_t size)
{
    ssize_t n;

    ASSERT(buf != NULL);
    ASSERT(size > 0);
    ASSERT(conn->recv_ready);

    for (;;) {
        n = nc_read(conn->fd, buf, size);

        log_verb("recv on conn:%p, fd:%d got %zd/%zu", conn, conn->fd, n, size);

        if (n > 0) {
            if (n < (ssize_t)size) {
                conn->recv_ready = 0;
            }
            conn->recv_bytes += (size_t)n;
            conn->recv_queue_bytes += (size_t)n;
            return n;
        }

        if (n == 0) {
            conn->recv_ready = 0;
            conn->eof = 1;
            log_info("recv on conn:%p fd:%d eof rb %zu sb %zu", conn, conn->fd,
                      conn->recv_bytes, conn->send_bytes);
            return n;
        }

        if (errno == EINTR) {
            log_verb("recv on conn:%p fd:%d not ready - eintr", conn, conn->fd);
            continue;
        } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
            conn->recv_ready = 0;
            log_verb("recv on conn:%p fd:%d not ready - eagain", conn, conn->fd);
            return NC_EAGAIN;
        } else {
            conn->recv_ready = 0;
            conn->err = errno;
            log_error("recv on conn:%p fd:%d failed: %s", conn, conn->fd, strerror(errno));
            return NC_ERROR;
        }
    }

    NOT_REACHED();
    return NC_ERROR;
}
예제 #6
0
파일: nc_connection.c 프로젝트: idning/ndb
static ssize_t
conn_send_buf(struct conn *conn, void *buf, size_t size)
{
    ssize_t n;

    ASSERT(buf != NULL);
    ASSERT(size > 0);
    ASSERT(conn->send_ready);

    for (;;) {
        n = nc_write(conn->fd, buf, size);

        log_verb("sendv on fd %d %zd of %zu",
                  conn->fd, n, size);

        if (n > 0) {
            if (n < (ssize_t)size) {
                conn->send_ready = 0;
            }
            conn->send_bytes += (size_t)n;
            return n;
        }

        if (n == 0) {
            log_warn("sendv on fd %d returned zero", conn->fd);
            conn->send_ready = 0;
            return 0;
        }

        if (errno == EINTR) {
            log_verb("sendv on fd %d not ready - eintr", conn->fd);
            continue;
        } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
            conn->send_ready = 0;
            log_verb("sendv on fd %d not ready - eagain", conn->fd);
            return NC_EAGAIN;
        } else {
            conn->send_ready = 0;
            conn->err = errno;
            log_error("sendv on fd %d failed: %s", conn->fd, strerror(errno));
            return NC_ERROR;
        }
    }

    NOT_REACHED();

    return NC_ERROR;
}
예제 #7
0
파일: process.c 프로젝트: sagar0/pelikan
static void
_process_get(struct response *rsp, struct request *req)
{
    struct bstring *key;
    struct response *r = rsp;
    uint32_t i;

    INCR(process_metrics, get);
    /* use chained responses, move to the next response if key is found. */
    for (i = 0; i < array_nelem(req->keys); ++i) {
        INCR(process_metrics, get_key);
        key = array_get(req->keys, i);
        if (_get_key(r, key)) {
            req->nfound++;
            r->cas = false;
            r = STAILQ_NEXT(r, next);
            if (r == NULL) {
                INCR(process_metrics, get_ex);
                log_warn("get response incomplete due to lack of rsp objects");
                return;
            }
            INCR(process_metrics, get_key_hit);
        } else {
            INCR(process_metrics, get_key_miss);
        }
    }
    r->type = RSP_END;

    log_verb("get req %p processed, %d out of %d keys found", req, req->nfound, i);
}
예제 #8
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Get an item from the item free q of the given slab with id.
 */
static struct item *
_slab_get_item_from_freeq(uint8_t id)
{
    struct slabclass *p; /* parent slabclass */
    struct item *it;

    if (!use_freeq) {
        return NULL;
    }

    p = &slabclass[id];

    if (p->nfree_itemq == 0) {
        return NULL;
    }

    it = SLIST_FIRST(&p->free_itemq);

    ASSERT(it->magic == ITEM_MAGIC);
    ASSERT(it->in_freeq);
    ASSERT(!(it->is_linked));

    it->in_freeq = 0;

    ASSERT(p->nfree_itemq > 0);
    p->nfree_itemq--;
    SLIST_REMOVE(&p->free_itemq, it, item, i_sle);
    PERSLAB_DECR(id, item_free);

    log_verb("get free q it %p at offset %"PRIu32" with id %"PRIu8, it,
            it->offset, it->id);

    return it;
}
예제 #9
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Get an item from the slab with a given id. We get an item either from:
 * 1. item free Q of given slab with id. or,
 * 2. current slab.
 * If the current slab is empty, we get a new slab from the slab allocator
 * and return the next item from this new slab.
 */
static struct item *
_slab_get_item(uint8_t id)
{
    struct slabclass *p;
    struct item *it;

    p = &slabclass[id];

    it = _slab_get_item_from_freeq(id);
    if (it != NULL) {
        return it;
    }

    if (p->next_item_in_slab == NULL && (_slab_get(id) != CC_OK)) {
        return NULL;
    }

    /* return item from current slab */
    it = p->next_item_in_slab;
    if (--p->nfree_item != 0) {
        p->next_item_in_slab = (struct item *)((char *)p->next_item_in_slab + p->size);
    } else {
        p->next_item_in_slab = NULL;
    }

    log_verb("get new it at offset %"PRIu32" with id %"PRIu8"",
              it->offset, it->id);

    return it;
}
예제 #10
0
파일: cmd_list.c 프로젝트: huayl/pelikan
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);
}
예제 #11
0
파일: nc_misc.c 프로젝트: idning/ndb
void
_nc_free(void *ptr, const char *name, int line)
{
    ASSERT(ptr != NULL);
    log_verb("free(%p) @ %s:%d", ptr, name, line);
    free(ptr);
}
예제 #12
0
파일: item.c 프로젝트: huayl/pelikan
static void
_item_delete(struct item **it)
{
    log_verb("delete it %p of id %"PRIu8, *it, (*it)->id);

    _item_unlink(*it);
    _item_dealloc(it);
}
예제 #13
0
파일: item.c 프로젝트: huayl/pelikan
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);
}
예제 #14
0
파일: slab.c 프로젝트: huayl/pelikan
static void
_slab_table_update(struct slab *slab)
{
    ASSERT(heapinfo.nslab < heapinfo.max_nslab);

    heapinfo.slab_table[heapinfo.nslab] = slab;
    heapinfo.nslab++;

    log_verb("new slab %p allocated at pos %u", slab,
              heapinfo.nslab - 1);
}
예제 #15
0
파일: item.c 프로젝트: huayl/pelikan
void
item_insert(struct item *it, const struct bstring *key)
{
    ASSERT(it != NULL && key != NULL);

    item_delete(key);

    _item_link(it);
    log_verb("insert it %p of id %"PRIu8" for key %.*s", it, it->id, key->len,
        key->data);
}
예제 #16
0
파일: item.c 프로젝트: huayl/pelikan
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);
}
예제 #17
0
파일: cmd_list.c 프로젝트: huayl/pelikan
void
cmd_list_delete(struct response *rsp, struct request *req, struct command *cmd)
{
    struct bstring *key = _get_key(req);
    struct element *reply = (struct element *)array_push(rsp->token);

    INCR(process_metrics, list_delete);

    if (item_delete(key)) {
        reply->bstr = str2bstr(RSP_OK);
        INCR(process_metrics, list_delete_deleted);
        log_verb("command '%.*s' '%.*s' succeeded", cmd->bstr.len,
                cmd->bstr.data, key->len, key->data);
    } else {
        reply->bstr = str2bstr(RSP_NOTFOUND);
        INCR(process_metrics, list_delete_notfound);
        log_verb("command '%.*s' '%.*s' completed as no-op, key not found",
                cmd->bstr.len, cmd->bstr.data, key->len, key->data);
    }

}
예제 #18
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;
    }
}
예제 #19
0
void
ring_array_destroy(struct ring_array **arr)
{
    log_verb("destroying ring array %p and freeing memory", *arr);

    if ((arr == NULL) || (*arr == NULL)) {
        log_warn("destroying NULL ring_array pointer");
        return;
    }

    cc_free(*arr);
    *arr = NULL;
}
예제 #20
0
파일: nc_connection.c 프로젝트: idning/ndb
void
conn_put(struct conn *conn)
{
    ASSERT(conn->fd < 0);
    ASSERT(STAILQ_EMPTY(&conn->recv_queue));
    ASSERT(STAILQ_EMPTY(&conn->send_queue));

    log_verb("put conn %p", conn);
    /* TODO: free mbuf here */

    nfree_connq++;
    TAILQ_INSERT_HEAD(&free_connq, conn, conn_tqe);
}
예제 #21
0
파일: nc_connection.c 프로젝트: idning/ndb
struct conn *
conn_get(void *owner)
{
    struct conn *conn;

    conn = _conn_get();
    if (conn == NULL) {
        return NULL;
    }

    conn->owner = owner;

    log_verb("get conn %p", conn);
    return conn;
}
예제 #22
0
파일: nc_misc.c 프로젝트: idning/ndb
void *
_nc_realloc(void *ptr, size_t size, const char *name, int line)
{
    void *p;

    ASSERT(size != 0);

    p = realloc(ptr, size);
    if (p == NULL) {
        log_error("realloc(%zu) failed @ %s:%d", size, name, line);
    } else {
        log_verb("realloc(%zu) at %p @ %s:%d", size, p, name, line);
    }

    return p;
}
예제 #23
0
파일: server.c 프로젝트: sagar0/pelikan
static inline void
_server_pipe_write(void)
{
    ASSERT(pipe_c != NULL);

    ssize_t status = pipe_send(pipe_c, "", 1);

    if (status == 0 || status == CC_EAGAIN) {
        /* retry write */
        log_verb("server core: retry send on pipe");
        event_add_write(ctx->evb, pipe_write_id(pipe_c), NULL);
    } else if (status == CC_ERROR) {
        /* other reasn write can't be done */
        log_error("could not write to pipe - %s", strerror(pipe_c->err));
    }

    /* else, pipe write succeeded and no action needs to be taken */
}
예제 #24
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);
}
예제 #25
0
파일: item.c 프로젝트: huayl/pelikan
item_rstatus_e
item_reserve(struct item **it_p, const struct bstring *key, const struct bstring
        *val, uint32_t vlen, uint8_t olen, proc_time_i expire_at)
{
    item_rstatus_e status;
    struct item *it;

    if ((status = _item_alloc(it_p, key->len, vlen, olen)) != ITEM_OK) {
        log_debug("item reservation failed");
        return status;
    }

    it = *it_p;

    _item_define(it, key, val, olen, expire_at);

    log_verb("reserve it %p of id %"PRIu8" for key '%.*s' optional len %"PRIu8,
            it, it->id,key->len, key->data, olen);

    return ITEM_OK;
}
예제 #26
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Put an item back into the slab by inserting into the item free Q.
 */
static void
_slab_put_item_into_freeq(struct item *it, uint8_t id)
{
    struct slabclass *p = &slabclass[id];

    ASSERT(id >= SLABCLASS_MIN_ID && id <= profile_last_id);
    ASSERT(item_to_slab(it)->id == id);
    ASSERT(!(it->is_linked));
    ASSERT(!(it->in_freeq));
    ASSERT(it->offset != 0);

    log_verb("put free q it %p at offset %"PRIu32" with id %"PRIu8, it,
            it->offset, it->id);

    it->in_freeq = 1;

    p->nfree_itemq++;
    SLIST_INSERT_HEAD(&p->free_itemq, it, i_sle);

    PERSLAB_INCR(id, item_free);
}
예제 #27
0
파일: item.c 프로젝트: huayl/pelikan
/*
 * Link an item into the hash table
 */
static void
_item_link(struct item *it)
{
    ASSERT(it->magic == ITEM_MAGIC);
    ASSERT(!(it->is_linked));
    ASSERT(!(it->in_freeq));

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

    it->is_linked = 1;
    slab_deref(item_to_slab(it)); /* slab ref'ed in _item_alloc */

    hashtable_put(it, hash_table);

    INCR(slab_metrics, item_linked_curr);
    INCR(slab_metrics, item_link);
    /* TODO(yao): how do we track optional storage? Separate or treat as val? */
    INCR_N(slab_metrics, item_keyval_byte, it->klen + it->vlen);
    INCR_N(slab_metrics, item_val_byte, it->vlen);
    PERSLAB_INCR_N(it->id, item_keyval_byte, it->klen + it->vlen);
    PERSLAB_INCR_N(it->id, item_val_byte, it->vlen);
}
예제 #28
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Evict by looking into least recently used queue of all slabs.
 */
static struct slab *
_slab_evict_lru(int id)
{
    struct slab *slab = _slab_lruq_head();
    int i = 0;

    while (slab != NULL && ++i < TRIES_MAX && !_slab_evict_ok(slab)) {
        slab = TAILQ_NEXT(slab, s_tqe);
    };

    if (slab == NULL) {
        /* warning here because eviction failure should be rare. This can
         * indicate there are dead/idle connections hanging onto items and
         * slab refcounts.
         */
        log_warn("can't find a slab for lru-evicting slab with %d tries", i);
    } else {
        log_verb("lru-evicting slab %p with id %u", slab, slab->id);
        _slab_evict_one(slab);
    }

    return slab;
}
예제 #29
0
파일: slab.c 프로젝트: huayl/pelikan
/*
 * Get a random slab from all active slabs and evict it for new allocation.
 *
 * Note that the slab_table enables us to have O(1) lookup for every slab in
 * the system. The inserts into the table are just appends - O(1) and there
 * are no deletes from the slab_table. These two constraints allows us to keep
 * our random choice uniform.
 */
static struct slab *
_slab_evict_rand(void)
{
    struct slab *slab;
    int i = 0;

    do {
        slab = _slab_table_rand();
    } while (slab != NULL && ++i < TRIES_MAX && !_slab_evict_ok(slab));

    if (slab == NULL) {
        /* warning here because eviction failure should be rare. This can
         * indicate there are dead/idle connections hanging onto items and
         * slab refcounts.
         */
        log_warn("can't find a slab for random-evicting slab with %d tries", i);
    } else {
        log_verb("random-evicting slab %p with id %u", slab, slab->id);
        _slab_evict_one(slab);
    }

    return slab;
}
예제 #30
0
파일: slab.c 프로젝트: huayl/pelikan
void
slab_setup(slab_options_st *options, slab_metrics_st *metrics)
{
    char *profile_str = SLAB_PROFILE;

    log_info("set up the %s module", SLAB_MODULE_NAME);

    if (slab_init) {
        log_warn("%s has already been set up, re-creating", SLAB_MODULE_NAME);
        slab_teardown();
    }

    log_verb("Slab header size: %d, item header size: %d", SLAB_HDR_SIZE,
            ITEM_HDR_SIZE);

    slab_metrics = metrics;

    if (options != NULL) {
        slab_size = option_uint(&options->slab_size);
        slab_mem = option_uint(&options->slab_mem);
        prealloc = option_bool(&options->slab_prealloc);
        evict_opt = option_uint(&options->slab_evict_opt);
        use_freeq = option_bool(&options->slab_use_freeq);
        profile_str = option_str(&options->slab_profile);
        item_min = option_uint(&options->slab_item_min);
        item_max = option_uint(&options->slab_item_max);
        item_growth = option_fpn(&options->slab_item_growth);
        max_ttl = option_uint(&options->slab_item_max_ttl);
        use_cas = option_bool(&options->slab_use_cas);
        hash_power = option_uint(&options->slab_hash_power);
    }

    hash_table = hashtable_create(hash_power);
    if (hash_table == NULL) {
        log_crit("Could not create hash table");
        goto error;
    }

    if (_slab_heapinfo_setup() != CC_OK) {
        log_crit("Could not setup slab heap info");
        goto error;
    }

    if (_slab_profile_setup(profile_str) != CC_OK) {
        log_crit("Could not setup slab profile");
        goto error;
    }

    if (_slab_slabclass_setup() != CC_OK) {
        log_crit("Could not setup slabclasses");
        goto error;
    }

    slab_init = true;

    return;

error:
    slab_teardown();
    exit(EX_CONFIG);
}