//参数值为使用到的slabclass数组元素个数 //为slabclass数组的每一个元素(使用到的元素)分配内存 static void slabs_preallocate (const unsigned int maxslabs) { int i; unsigned int prealloc = 0; /* pre-allocate a 1MB slab in every size class so people don't get confused by non-intuitive "SERVER_ERROR out of memory" messages. this is the most common question on the mailing list. if you really don't want this, you can rebuild without these three lines. */ //遍历slabclass数组 for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) { if (++prealloc > maxslabs)//当然是只遍历使用了的数组元素 return; if (do_slabs_newslab(i) == 0) {//为每一个slabclass_t分配一个内存页 //如果分配失败,将退出程序.因为这个预分配的内存是后面程序运行的基础 //如果这里分配失败了,后面的代码无从执行。所以就直接退出程序 fprintf(stderr, "Error while preallocating slab memory!\n" "If using -L or other prealloc options, max memory must be " "at least %d megabytes.\n", power_largest); exit(1); } } }
void* Slab::do_slabs_alloc(size_t size, unsigned int id) { void* ret = 0; struct base_item *it = 0; slabclass& p = mem_base[id]; if (id < POWER_SMALLEST || id > POWER_LARGEST) { return (void*)0; } //查看是否freelist上没有东西了 if (! (p.sl_curr != 0 || do_slabs_newslab(id) != 0) ) { return (void*)0; } else if (p.sl_curr != 0) { //从freelist取出一个给他 it = (struct base_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; } 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; 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; }
/* This calculation ends up adding sizeof(void *) to the item size. */ static void *do_slabs_alloc_chunked(const size_t size, slabclass_t *p, unsigned int id) { void *ret = NULL; item *it = NULL; int x; int csize = p->size - sizeof(item_chunk); unsigned int chunks_req = size / csize; if (size % csize != 0) chunks_req++; while (p->sl_curr < chunks_req) { if (do_slabs_newslab(id) == 0) break; } if (p->sl_curr >= chunks_req) { item_chunk *chunk = NULL; /* Configure the head item in the chain. */ it = (item *)p->slots; p->slots = it->next; if (it->next) it->next->prev = 0; /* Squirrel away the "top chunk" into h_next for now */ it->h_next = (item *)p->slots; assert(it->h_next != 0); chunk = (item_chunk *) it->h_next; /* roll down the chunks, marking them as such. */ for (x = 0; x < chunks_req-1; x++) { chunk->it_flags &= ~ITEM_SLABBED; chunk->it_flags |= ITEM_CHUNK; /* Chunks always have a direct reference to the head item */ chunk->head = it; chunk->size = p->size - sizeof(item_chunk); chunk->used = 0; chunk = chunk->next; } /* The final "next" is now the top of the slab freelist */ p->slots = chunk; if (chunk && chunk->prev) { /* Disconnect the final chunk from the chain */ chunk->prev->next = 0; chunk->prev = 0; } it->it_flags &= ~ITEM_SLABBED; it->it_flags |= ITEM_CHUNKED; it->refcount = 1; p->sl_curr -= chunks_req; ret = (void *)it; } else { ret = NULL; } return ret; }
static void slabs_preallocate(const unsigned int maxslabs) { int i; unsigned int prealloc = 0; /* pre-allocate a 1MB slab in every size class so people don't get confused by non-intuitive "SERVER_ERROR out of memory" messages. this is the most common question on the mailing list. if you really don't want this, you can rebuild without these three lines. */ for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) { if (++prealloc > maxslabs) return; do_slabs_newslab(i); } /* slab class 0 is used for collection items and small-size kv items */ do_slabs_newslab(0); }
/*@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; }
void Slab::slabs_preallocate(const unsigned int maxslabs) { int i; unsigned int prealloc = 0; for ( i = POWER_SMALLEST; i < power_largest; i++) { if (++prealloc > maxslabs) return; if (do_slabs_newslab(i) == 0) { std::cerr << "Error while preallocating slab class "<< i << " memory!\n"; exit(1); } } }
/*@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, 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; }
/*@null@*/ static void *do_slabs_alloc(slabs_t* pst, const size_t size, unsigned int id) { slabclass_t *p; void *ret = NULL; slabheader_t *it = NULL; if (id < POWER_SMALLEST || id > pst->power_largest) { //MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); return NULL; } p = &pst->slabclass[id]; //assert(p->sl_curr == 0 || ((slabheader_t*)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 */ if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(pst, id) != 0)) { /* We don't have more memory available */ ret = NULL; } else if (p->sl_curr != 0) { /* return off our freelist */ it = (slabheader_t*)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); } //printf("alloc ps:%p sid:%u p:%p np:%p cnt:%u used:%lu rest:%u \n", pst, id, ret, p->end_page_ptr, p->sl_curr, p->requested, p->end_page_free); 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; }
//分配每个slab的内存空间,maxslabs表示已经初始化的slab的最大编号,即下标 static void slabs_preallocate (const unsigned int maxslabs) { int i; unsigned int prealloc = 0; /* pre-allocate a 1MB slab in every size class so people don't get confused by non-intuitive "SERVER_ERROR out of memory" messages. this is the most common question on the mailing list. if you really don't want this, you can rebuild without these three lines. */ for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) { if (++prealloc > maxslabs) return; //执行分配操作,对第i个slabclass执行分配操作 if (do_slabs_newslab(i) == 0) { fprintf(stderr, "Error while preallocating slab memory!\n" "If using -L or other prealloc options, max memory must be " "at least %d megabytes.\n", power_largest); exit(1); } } }
/*@null@*/ void *do_slabs_alloc(const size_t size) { slabclass_t *p; unsigned int id = slabs_clsid(size); if (id < POWER_SMALLEST || id > power_largest) return NULL; p = &slabclass[id]; assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0); #ifdef USE_SYSTEM_MALLOC if (mem_limit && mem_malloced + size > mem_limit) return 0; mem_malloced += size; return malloc(size); #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)) return 0; /* return off our freelist, if we have one */ if (p->sl_curr != 0) return p->slots[--p->sl_curr]; /* if we recently allocated a whole page, return from that */ if (p->end_page_ptr) { void *ptr = p->end_page_ptr; if (--p->end_page_free != 0) { p->end_page_ptr += p->size; } else { p->end_page_ptr = 0; } return ptr; } return NULL; /* shouldn't ever get here */ }