/*@null@*/ static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); #ifdef USE_SYSTEM_MALLOC if (mem_limit && mem_malloced + size > mem_limit) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); return 0; } mem_malloced += size; ret = malloc(size); MEMCACHED_SLABS_ALLOCATE(size, id, 0, ret); return ret; #endif /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; p->sl_curr--; ret = (void *)it; } else { /* if we recently allocated a whole page, return from that */ assert(p->end_page_ptr != NULL); ret = p->end_page_ptr; if (--p->end_page_free != 0) { p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size; } else { p->end_page_ptr = 0; } } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
/*@null@*/ static void *do_slabs_alloc(struct default_engine *engine, const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; if (id < POWER_SMALLEST || id > engine->slabs.power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &engine->slabs.slabclass[id]; #ifdef USE_SYSTEM_MALLOC if (engine->slabs.mem_limit && engine->slabs.mem_malloced + size > engine->slabs.mem_limit) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); return 0; } engine->slabs.mem_malloced += size; ret = malloc(size); MEMCACHED_SLABS_ALLOCATE(size, id, 0, ret); return ret; #endif /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(engine, id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ ret = p->slots[--p->sl_curr]; } else { /* if we recently allocated a whole page, return from that */ cb_assert(p->end_page_ptr != NULL); ret = p->end_page_ptr; if (--p->end_page_free != 0) { p->end_page_ptr = ((unsigned char *)p->end_page_ptr) + p->size; } else { p->end_page_ptr = 0; } } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
/*@null@*/ static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ #ifdef TEST_LRU item *it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; p->sl_curr--; ret = (void *)it; #endif #ifdef TEST_CLOCK /* return off our freelist */ slabbed_item* sl_it = (slabbed_item *)p->slots; p->slots = sl_it->next; if (sl_it->next) sl_it->next->prev = 0; p->sl_curr--; ret = (void *)sl_it; #endif } else { /* if we recently allocated a whole page, return from that */ assert(p->end_page_ptr != NULL); ret = p->end_page_ptr; if (--p->end_page_free != 0) { p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size; } else { p->end_page_ptr = 0; } /* item *it = (item *)ret; */ /* reset_version(it); */ } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
/*@null@*/ static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); printf("%s:%d returning NULL from here\n", __func__, __LINE__); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: sl_curr = %u\n", __func__, __LINE__, p->sl_curr); /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d returning NULL from here\n", __func__, __LINE__); ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ #ifdef HOPSCOTCH_CLOCK slabbed_item* sl_it = (slabbed_item *)p->slots; p->slots = sl_it->next; if (sl_it->next) sl_it->next->prev = 0; //DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: before it_flags = %u\n", __func__, __LINE__, sl_it->it_flags); //__sync_fetch_and_and(&sl_it->it_flags, ~ITEM_SLABBED); //DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: after it_flags = %u\n", __func__, __LINE__, sl_it->it_flags); ret = (void *)sl_it; #else item *it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; /* Kill flag and initialize refcount here for lock safety in slab * mover's freeness detection. */ DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: before it_flags = %u\n", __func__, __LINE__, sl_it->it_flags); it->it_flags &= ~ITEM_SLABBED; DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: after it_flags = %u\n", __func__, __LINE__, sl_it->it_flags); it->refcount = 1; ret = (void *)it; #endif p->sl_curr--; } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d returning ret = %p from here\n", __func__, __LINE__, ret); return ret; }
/*@null@*/ static void *do_slabs_alloc(const size_t size, unsigned int id, uint64_t *total_bytes, unsigned int flags) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); if (total_bytes != NULL) { *total_bytes = p->requested; } if (size <= p->size) { /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ if (p->sl_curr == 0 && flags != SLABS_ALLOC_NO_NEWPAGE) { do_slabs_newslab(id); } if (p->sl_curr != 0) { /* return off our freelist */ it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; /* Kill flag and initialize refcount here for lock safety in slab * mover's freeness detection. */ it->it_flags &= ~ITEM_SLABBED; it->refcount = 1; p->sl_curr--; ret = (void *)it; } else { ret = NULL; } } else { /* Dealing with a chunked item. */ ret = do_slabs_alloc_chunked(size, p, id); } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
// 从slabclass中申请size大小的空间 static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; // 可以看出,有slab中的空间不仅只能通过slab_list获得,还可以通过slots来获得, // 因为free出来的item是放在slots中的,即slots中的item其实是存储slab中的,由于 // 不好判断slab中的item是否被释放,所以搞出来一个slots来存储释放的item,这样就 // 不需要判断,而直接用即可。 这真是将指针的好处体现得淋漓尽致 assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ // 这个新版本已经将所有用户内存分配都改为从slots中进行了,在newslab中的时候 // 已经将item信息全部存储slots中了。 // 当前sl_curr为0时,即没有了item,然后newslab,这样又有item放进去了,所以下面可以继续 // 分配 if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ // 这里是从slots的头开始分配的 it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; p->sl_curr--; ret = (void *)it; } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
/*@null@*/ static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ /* 确保最后一个slab 有空闲的chunk */ if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; } //从slabclass_t的空闲item链表中获取一个item else if (p->sl_curr != 0) { /* return off our freelist */ it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; p->sl_curr--; ret = (void *)it; } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
// 从指定的 slabclass, 即 slabclass[id], 分配大小为 size 的内存块供申请者使用. // // 分配的原则是, 优先从 slots 指向的空闲链表中分配, 空闲链表没有, 才从 slab 中分配一个空闲的 chunk. static void *do_slabs_alloc(const size_t size, unsigned int id, unsigned int *total_chunks) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); *total_chunks = p->slabs * p->perslab; /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ // p->sl_curr == 0 && do_slabs_newslab(id) == 0 // TODO 若分配新的slab后,什么都不干? if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; /* Kill flag and initialize refcount here for lock safety in slab * mover's freeness detection. */ it->it_flags &= ~ITEM_SLABBED; it->refcount = 1; p->sl_curr--; ret = (void *)it; } if (ret) { p->requested += size; MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }
//向slabclass申请一个item。在调用该函数之前,已经调用slabs_clsid函数确定 //本次申请是向哪个slabclass_t申请item了,参数id就是指明是向哪个slabclass_t //申请item。如果该slabclass_t是有空闲item,那么就从空闲的item队列中分配一个 //如果没有空闲item,那么就申请一个内存页。再从新申请的页中分配一个item //返回值为得到的item,如果没有内存了,返回NULL static void *do_slabs_alloc(const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) {//下标越界 MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0); /* fail unless we have space at the end of a recently allocated page, we have something on our freelist, or we could allocate a new page */ //如果p->sl_curr等于0,就说明该slabclass_t没有空闲的item了 //此时需要调用do_slabs_newslab申请一个内存页 if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ //当p->sl_curr等于0并且do_slabs_newslab的返回值等于0时,进入这里 ret = NULL; } else if (p->sl_curr != 0) { //除非do_slabs_newslab调用失败,否则都会来到这里.无论一开始sl_curr是否为0。 //p->slots指向第一个空闲的item,此时要把第一个空闲的item分配出去 /* return off our freelist */ it = (item *)p->slots; p->slots = it->next;//slots指向下一个空闲的item if (it->next) it->next->prev = 0; p->sl_curr--;//空闲数目减一 ret = (void *)it; } if (ret) { p->requested += size;//增加本slabclass分配出去的字节数 MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); } else { MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); } return ret; }