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; }
struct item * slab_get_item(uint8_t cid) { rstatus_t status; struct slabclass *c; struct slabinfo *sinfo; struct slab *slab; ASSERT(cid >= SLABCLASS_MIN_ID && cid < nctable); c = &ctable[cid]; if (itemx_empty()) { status = slab_evict(); if (status != FC_OK) { return NULL; } } if (!TAILQ_EMPTY(&c->partial_msinfoq)) { return _slab_get_item(cid); } if (!TAILQ_EMPTY(&free_msinfoq)) { /* move memory slab from free to partial q */ sinfo = TAILQ_FIRST(&free_msinfoq); ASSERT(nfree_msinfoq > 0); nfree_msinfoq--; TAILQ_REMOVE(&free_msinfoq, sinfo, tqe); /* init partial sinfo */ TAILQ_INSERT_HEAD(&c->partial_msinfoq, sinfo, tqe); /* sid is already initialized by slab_init */ /* addr is already initialized by slab_init */ sinfo->nalloc = 0; sinfo->nfree = 0; sinfo->cid = cid; /* mem is already initialized by slab_init */ ASSERT(sinfo->mem == 1); /* init slab of partial sinfo */ slab = slab_from_maddr(sinfo->addr, false); slab->magic = SLAB_MAGIC; slab->cid = cid; /* unused[] is left uninitialized */ slab->sid = sinfo->sid; /* data[] is initialized on-demand */ return _slab_get_item(cid); } ASSERT(!TAILQ_EMPTY(&full_msinfoq)); ASSERT(nfull_msinfoq > 0); status = slab_drain(); if (status != FC_OK) { return NULL; } return slab_get_item(cid); }
/* * 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; } }