//slabclass_t中slab的数目是慢慢增多的。该函数的作用就是为slabclass_t申请多一个slab //参数id指明是slabclass数组中的那个slabclass_t static int do_slabs_newslab(const unsigned int id) { slabclass_t *p = &slabclass[id]; //settings.slab_reassign的默认值为false,这里就采用false int len = settings.slab_reassign ? settings.item_size_max : p->size * p->perslab;//其积 <= settings.item_size_max char *ptr; //mem_malloced的值通过环境变量设置,默认为0 if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) ||//增长slab_list(失败返回0)。一般都会成功,除非无法分配内存 ((ptr = memory_allocate((size_t)len)) == 0)) {//分配len字节内存(也就是一个页) MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len);//清零内存块是必须的 //将这块内存切成一个个的item,当然item的大小有id所控制 split_slab_page_into_freelist(ptr, id); //将分配得到的内存页交由slab_list掌管 p->slab_list[p->slabs++] = ptr; mem_malloced += len; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
/** * 为slabclass[id]分配一个新的slab,成功返回1,否则返回0 * * 1. 确定slab的长度len * 2. 分配len大小的内存(预分配的内存中划分或者调malloc()分配) * 3. 把所分配的内存初始化成item链表,链接到slabclass[id]的slot中 * 4. slabclass[i]属性的更新:slabs数增1 * 5. 已分配内存数的更新 */ static int do_slabs_newslab(const unsigned int id) { slabclass_t *p = &slabclass[id]; //指向第i个slabclass int len = settings.slab_reassign ? settings.item_size_max //是否开启可自定slab大小,否则使用默认的大小1M : p->size * p->perslab; char *ptr; //grow_slab_list初始化slabclass的slab_list,而slab_list中的指针指向每个slab //memory_allocate从内存池申请1M的空间 if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) { MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); //将申请到的1M空间按照slabclass的size进行切分 split_slab_page_into_freelist(ptr, id); p->slab_list[p->slabs++] = ptr;//循环分配 mem_malloced += len; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
static int do_slabs_newslab(const unsigned int id) { slabclass_t *p = &slabclass[id]; slabclass_t *g = &slabclass[SLAB_GLOBAL_PAGE_POOL]; int len = settings.slab_reassign ? settings.item_size_max : p->size * p->perslab; char *ptr; if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0 && g->slabs == 0)) { mem_limit_reached = true; MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } if ((grow_slab_list(id) == 0) || (((ptr = get_page_from_global_pool()) == NULL) && ((ptr = memory_allocate((size_t)len)) == 0))) { MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); split_slab_page_into_freelist(ptr, id); p->slab_list[p->slabs++] = ptr; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
static int do_slabs_newslab(const unsigned int id) { slabclass_t *p = &slabclass[id]; int len = settings.slab_reassign ? settings.item_size_max : p->size * p->perslab; char *ptr; DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: mem_limit = %u, len = %u\n", __func__, __LINE__, (unsigned int)mem_limit, (unsigned int)len); DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: p->slabs = %u\n", __func__, __LINE__, p->slabs); if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) { mem_limit_reached = true; MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: mem_limit = %u, mem_malloced = %u, len = %d\n", __func__, __LINE__, (unsigned int)mem_limit, (unsigned int)mem_malloced, len); DBG_INFO(DBG_ASSOC_HOPSCOTCH, "%s:%d: returning 0\n", __func__, __LINE__); return 0; } memset(ptr, 0, (size_t)len); // TODO: Should this be commented? split_slab_page_into_freelist(ptr, id); p->slab_list[p->slabs++] = ptr; #ifdef HOPSCOTCH_CLOCK p->clock_max = p->slabs * p->perslab; #endif mem_malloced += len; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
static void slab_rebalance_finish(void) { slabclass_t *s_cls; slabclass_t *d_cls; pthread_mutex_lock(&cache_lock); pthread_mutex_lock(&slabs_lock); s_cls = &slabclass[slab_rebal.s_clsid]; d_cls = &slabclass[slab_rebal.d_clsid]; /* At this point the stolen slab is completely clear */ //相当于把指针赋NULL值 s_cls->slab_list[s_cls->killing - 1] = s_cls->slab_list[s_cls->slabs - 1]; s_cls->slabs--;//源slab class的内存页数减一 s_cls->killing = 0; //内存页所有字节清零,这个也很重要的 memset(slab_rebal.slab_start, 0, (size_t)settings.item_size_max); //将slab_rebal.slab_start指向的一个页内存馈赠给目标slab class //slab_rebal.slab_start指向的页是从源slab class中得到的。 d_cls->slab_list[d_cls->slabs++] = slab_rebal.slab_start; //按照目标slab class的item尺寸进行划分这个页,并且将这个页的 //内存并入到目标slab class的空闲item队列中 split_slab_page_into_freelist(slab_rebal.slab_start, slab_rebal.d_clsid); //清零 slab_rebal.done = 0; slab_rebal.s_clsid = 0; slab_rebal.d_clsid = 0; slab_rebal.slab_start = NULL; slab_rebal.slab_end = NULL; slab_rebal.slab_pos = NULL; slab_rebalance_signal = 0;//rebalance线程完成工作后,再次进入休眠状态 pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); STATS_LOCK(); stats.slab_reassign_running = false; stats.slabs_moved++; STATS_UNLOCK(); if (settings.verbose > 1) { fprintf(stderr, "finished a slab move\n"); } }
static void slab_rebalance_finish(void) { slabclass_t *s_cls; slabclass_t *d_cls; pthread_mutex_lock(&cache_lock); pthread_mutex_lock(&slabs_lock); s_cls = &slabclass[slab_rebal.s_clsid]; d_cls = &slabclass[slab_rebal.d_clsid]; /* At this point the stolen slab is completely clear */ s_cls->slab_list[s_cls->killing - 1] = s_cls->slab_list[s_cls->slabs - 1]; s_cls->slabs--; s_cls->killing = 0; memset(slab_rebal.slab_start, 0, (size_t)settings.item_size_max); d_cls->slab_list[d_cls->slabs++] = slab_rebal.slab_start; split_slab_page_into_freelist(slab_rebal.slab_start, slab_rebal.d_clsid); slab_rebal.done = 0; slab_rebal.s_clsid = 0; slab_rebal.d_clsid = 0; slab_rebal.slab_start = NULL; slab_rebal.slab_end = NULL; slab_rebal.slab_pos = NULL; slab_rebalance_signal = 0; pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); STATS_LOCK(); stats.slab_reassign_running = false; stats.slabs_moved++; STATS_UNLOCK(); if (settings.verbose > 1) { fprintf(stderr, "finished a slab move\n"); } }
int Slab::do_slabs_newslab(unsigned int id) { slabclass& p = mem_base[id]; int len = p.size * p.perslab; char* ptr; //异常情况 //内存限制不为0,申请大小总计已超过限制,并且已经申请了一些slab数 if ((mem_limit && mem_malloced+len > mem_limit && p.slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) { return 0; } memset(ptr, 0, (size_t)len); //把内存分解为chunk split_slab_page_into_freelist(ptr, id); p.slab_list[p.slabs++] = ptr; mem_malloced += len; return 1; }
static int do_slabs_newslab(const unsigned int id) { slabclass_t *p = &slabclass[id]; int len = settings.slab_reassign ? settings.item_size_max : p->size * p->perslab; char *ptr; if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || (grow_slab_list(id) == 0) || ((ptr = memory_allocate((size_t)len)) == 0)) { MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); split_slab_page_into_freelist(ptr, id); p->slab_list[p->slabs++] = ptr; mem_malloced += len; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
static void slab_rebalance_finish(void) { slabclass_t *s_cls; slabclass_t *d_cls; int x; uint32_t rescues; uint32_t evictions_nomem; uint32_t inline_reclaim; pthread_mutex_lock(&slabs_lock); s_cls = &slabclass[slab_rebal.s_clsid]; d_cls = &slabclass[slab_rebal.d_clsid]; #ifdef DEBUG_SLAB_MOVER /* If the algorithm is broken, live items can sneak in. */ slab_rebal.slab_pos = slab_rebal.slab_start; while (1) { item *it = slab_rebal.slab_pos; assert(it->it_flags == (ITEM_SLABBED|ITEM_FETCHED)); assert(memcmp(ITEM_key(it), "deadbeef", 8) == 0); it->it_flags = ITEM_SLABBED|ITEM_FETCHED; slab_rebal.slab_pos = (char *)slab_rebal.slab_pos + s_cls->size; if (slab_rebal.slab_pos >= slab_rebal.slab_end) break; } #endif /* At this point the stolen slab is completely clear. * We always kill the "first"/"oldest" slab page in the slab_list, so * shuffle the page list backwards and decrement. */ s_cls->slabs--; for (x = 0; x < s_cls->slabs; x++) { s_cls->slab_list[x] = s_cls->slab_list[x+1]; } d_cls->slab_list[d_cls->slabs++] = slab_rebal.slab_start; /* Don't need to split the page into chunks if we're just storing it */ if (slab_rebal.d_clsid > SLAB_GLOBAL_PAGE_POOL) { memset(slab_rebal.slab_start, 0, (size_t)settings.item_size_max); split_slab_page_into_freelist(slab_rebal.slab_start, slab_rebal.d_clsid); } else if (slab_rebal.d_clsid == SLAB_GLOBAL_PAGE_POOL) { /* mem_malloc'ed might be higher than mem_limit. */ memory_release(); } slab_rebal.done = 0; slab_rebal.s_clsid = 0; slab_rebal.d_clsid = 0; slab_rebal.slab_start = NULL; slab_rebal.slab_end = NULL; slab_rebal.slab_pos = NULL; evictions_nomem = slab_rebal.evictions_nomem; inline_reclaim = slab_rebal.inline_reclaim; rescues = slab_rebal.rescues; slab_rebal.evictions_nomem = 0; slab_rebal.inline_reclaim = 0; slab_rebal.rescues = 0; slab_rebalance_signal = 0; pthread_mutex_unlock(&slabs_lock); STATS_LOCK(); stats.slabs_moved++; stats.slab_reassign_rescues += rescues; stats.slab_reassign_evictions_nomem += evictions_nomem; stats.slab_reassign_inline_reclaim += inline_reclaim; stats_state.slab_reassign_running = false; STATS_UNLOCK(); if (settings.verbose > 1) { fprintf(stderr, "finished a slab move\n"); } }