static int do_slabs_newslab(const unsigned int id, bool disk_item) { slabclass_t *p = &slabclass[id]; int len = settings.slab_reassign ? settings.item_size_max : p->size * p->perslab; char *ptr; if (disk_item) { if ((disk_item_mem_limit && disk_item_mem_malloced + len > disk_item_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; } disk_item_mem_malloced += len; } else { 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; } mem_malloced += len; } memset(ptr, 0, (size_t)len); p->end_page_ptr = ptr; p->end_page_free = p->perslab; 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]; #ifdef ALLOW_SLABS_REASSIGN int len = POWER_BLOCK; #else int len = p->size * p->perslab; #endif 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); p->end_page_ptr = ptr; p->end_page_free = p->perslab; 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]; #ifdef ALLOW_SLABS_REASSIGN int len = POWER_BLOCK; #else int len = p->size * p->perslab; #endif char *ptr; if (mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) return 0; if (grow_slab_list(id) == 0) return 0; ptr = malloc((size_t)len); if (ptr == 0) return 0; memset(ptr, 0, (size_t)len); p->end_page_ptr = ptr; p->end_page_free = p->perslab; p->slab_list[p->slabs++] = ptr; mem_malloced += len; 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; }
//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; }
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 int do_slabs_newslab(slabs_t* pst, const unsigned int id) { slabclass_t *p = &pst->slabclass[id]; //int len = settings.slab_reassign ? settings.item_size_max // : p->size * p->perslab; int len = p->size * p->perslab; char *ptr; if ((pst->mem_limit && pst->mem_malloced + len > pst->mem_limit && p->slabs > 0) || (grow_slab_list(pst, id) == 0) || ((ptr = memory_allocate(pst, (size_t)len)) == 0)) { //MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); p->end_page_ptr = ptr; p->end_page_free = p->perslab; p->slab_list[p->slabs++] = ptr; pst->mem_malloced += len; //MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
static int slab_rebalance_start(void) { slabclass_t *s_cls; int no_go = 0; pthread_mutex_lock(&cache_lock); pthread_mutex_lock(&slabs_lock); if (slab_rebal.s_clsid < POWER_SMALLEST || slab_rebal.s_clsid > power_largest || slab_rebal.d_clsid < POWER_SMALLEST || slab_rebal.d_clsid > power_largest || slab_rebal.s_clsid == slab_rebal.d_clsid)//非法下标索引 no_go = -2; s_cls = &slabclass[slab_rebal.s_clsid]; //为这个目标slab class增加一个页表项都失败,那么就 //根本无法为之增加一个页了 if (!grow_slab_list(slab_rebal.d_clsid)) { no_go = -1; } if (s_cls->slabs < 2)//目标slab class页数太少了,无法分一个页给别人 no_go = -3; if (no_go != 0) { pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); return no_go; /* Should use a wrapper function... */ } //标志将源slab class的第几个内存页分给目标slab class //这里是默认是将第一个内存页分给目标slab class s_cls->killing = 1; //记录要移动的页的信息。slab_start指向页的开始位置。slab_end指向页 //的结束位置。slab_pos则记录当前处理的位置(item) slab_rebal.slab_start = s_cls->slab_list[s_cls->killing - 1]; slab_rebal.slab_end = (char *)slab_rebal.slab_start + (s_cls->size * s_cls->perslab); slab_rebal.slab_pos = slab_rebal.slab_start; slab_rebal.done = 0; /* Also tells do_item_get to search for items in this slab */ slab_rebalance_signal = 2;//要rebalance线程接下来进行内存页移动 if (settings.verbose > 1) { fprintf(stderr, "Started a slab rebalance\n"); } pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); STATS_LOCK(); stats.slab_reassign_running = true; STATS_UNLOCK(); return 0; }
static int slab_rebalance_start(void) { slabclass_t *s_cls; slabclass_t *d_cls; int no_go = 0; pthread_mutex_lock(&cache_lock); pthread_mutex_lock(&slabs_lock); if (slab_rebal.s_clsid < POWER_SMALLEST || slab_rebal.s_clsid > power_largest || slab_rebal.d_clsid < POWER_SMALLEST || slab_rebal.d_clsid > power_largest || slab_rebal.s_clsid == slab_rebal.d_clsid) no_go = -2; s_cls = &slabclass[slab_rebal.s_clsid]; d_cls = &slabclass[slab_rebal.d_clsid]; if (d_cls->end_page_ptr || s_cls->end_page_ptr || !grow_slab_list(slab_rebal.d_clsid)) { no_go = -1; } if (s_cls->slabs < 2) no_go = -3; if (no_go != 0) { pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); return no_go; /* Should use a wrapper function... */ } s_cls->killing = 1; slab_rebal.slab_start = s_cls->slab_list[s_cls->killing - 1]; slab_rebal.slab_end = (char *)slab_rebal.slab_start + (s_cls->size * s_cls->perslab); slab_rebal.slab_pos = slab_rebal.slab_start; slab_rebal.done = 0; /* Also tells do_item_get to search for items in this slab */ slab_rebalance_signal = 2; if (settings.verbose > 1) { fprintf(stderr, "Started a slab rebalance\n"); } pthread_mutex_unlock(&slabs_lock); pthread_mutex_unlock(&cache_lock); STATS_LOCK(); stats.slab_reassign_running = true; STATS_UNLOCK(); return 0; }
static int slab_rebalance_start(void) { slabclass_t *s_cls; int no_go = 0; pthread_mutex_lock(&slabs_lock); if (slab_rebal.s_clsid < POWER_SMALLEST || slab_rebal.s_clsid > power_largest || slab_rebal.d_clsid < SLAB_GLOBAL_PAGE_POOL || slab_rebal.d_clsid > power_largest || slab_rebal.s_clsid == slab_rebal.d_clsid) no_go = -2; s_cls = &slabclass[slab_rebal.s_clsid]; if (!grow_slab_list(slab_rebal.d_clsid)) { no_go = -1; } if (s_cls->slabs < 2) no_go = -3; if (no_go != 0) { pthread_mutex_unlock(&slabs_lock); return no_go; /* Should use a wrapper function... */ } /* Always kill the first available slab page as it is most likely to * contain the oldest items */ slab_rebal.slab_start = s_cls->slab_list[0]; slab_rebal.slab_end = (char *)slab_rebal.slab_start + (s_cls->size * s_cls->perslab); slab_rebal.slab_pos = slab_rebal.slab_start; slab_rebal.done = 0; /* Also tells do_item_get to search for items in this slab */ slab_rebalance_signal = 2; if (settings.verbose > 1) { fprintf(stderr, "Started a slab rebalance\n"); } pthread_mutex_unlock(&slabs_lock); STATS_LOCK(); stats_state.slab_reassign_running = true; STATS_UNLOCK(); return 0; }
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(struct default_engine *engine, const unsigned int id) { slabclass_t *p = &engine->slabs.slabclass[id]; int len = p->size * p->perslab; char *ptr; if ((engine->slabs.mem_limit && engine->slabs.mem_malloced + len > engine->slabs.mem_limit && p->slabs >= p->rsvd_slabs) || (grow_slab_list(engine, id) == 0) || ((ptr = memory_allocate(engine, (size_t)len)) == 0)) { MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); p->end_page_ptr = ptr; p->end_page_free = p->perslab; p->slab_list[p->slabs++] = ptr; engine->slabs.mem_malloced += len; if ((engine->slabs.mem_limit <= engine->slabs.mem_malloced) || ((engine->slabs.mem_limit - engine->slabs.mem_malloced) < engine->slabs.mem_reserved)) { if (engine->slabs.slabclass[sm_anchor.blck_clsid].rsvd_slabs == 0) { /* undefined */ /* define the reserved slab count of slab class 0 */ slabclass_t *z = &engine->slabs.slabclass[sm_anchor.blck_clsid]; unsigned int additional_slabs = (z->slabs/100) * RESERVED_SLAB_RATIO; if (additional_slabs < RESERVED_SLABS) additional_slabs = RESERVED_SLABS; z->rsvd_slabs = z->slabs + additional_slabs; sm_anchor.free_limit_space = (additional_slabs * z->perslab) * sm_anchor.blck_tsize; sm_anchor.free_chunk_space = sm_anchor.free_limit_space + (z->sl_curr + z->end_page_free) * sm_anchor.blck_tsize; } } MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
int slabs_newslab(unsigned int id) { slabclass_t *p = &slabclass[id]; int num = p->perslab; int len = POWER_BLOCK; char *ptr; if (mem_limit && mem_malloced + len > mem_limit) return 0; if (! grow_slab_list(id)) return 0; ptr = malloc(len); if (ptr == 0) return 0; memset(ptr, 0, len); p->end_page_ptr = ptr; p->end_page_free = num; p->slab_list[p->slabs++] = ptr; mem_malloced += len; return 1; }
static int do_slabs_newslab(struct default_engine *engine, const unsigned int id) { slabclass_t *p = &engine->slabs.slabclass[id]; int len = p->size * p->perslab; char *ptr; if ((engine->slabs.mem_limit && engine->slabs.mem_malloced + len > engine->slabs.mem_limit && p->slabs > 0) || (grow_slab_list(engine, id) == 0) || ((ptr = memory_allocate(engine, (size_t)len)) == 0)) { MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); return 0; } memset(ptr, 0, (size_t)len); p->end_page_ptr = ptr; p->end_page_free = p->perslab; p->slab_list[p->slabs++] = ptr; engine->slabs.mem_malloced += len; MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); return 1; }
/* 1 = success 0 = fail -1 = tried. busy. send again shortly. */ int slabs_reassign(unsigned char srcid, unsigned char dstid) { void *slab, *slab_end; slabclass_t *p, *dp; void *iter; int was_busy = 0; if (srcid < POWER_SMALLEST || srcid > POWER_LARGEST || dstid < POWER_SMALLEST || dstid > POWER_LARGEST) return 0; p = &slabclass[srcid]; dp = &slabclass[dstid]; /* fail if src still populating, or no slab to give up in src */ if (p->end_page_ptr || ! p->slabs) return 0; /* fail if dst is still growing or we can't make room to hold its new one */ if (dp->end_page_ptr || ! grow_slab_list(dstid)) return 0; if (p->killing == 0) p->killing = 1; slab = p->slab_list[p->killing-1]; slab_end = slab + POWER_BLOCK; for (iter=slab; iter<slab_end; iter+=p->size) { item *it = (item *) iter; if (it->slabs_clsid) { if (it->refcount) was_busy = 1; item_unlink(it); } } /* go through free list and discard items that are no longer part of this slab */ { int fi; for (fi=p->sl_curr-1; fi>=0; fi--) { if (p->slots[fi] >= slab && p->slots[fi] < slab_end) { p->sl_curr--; if (p->sl_curr > fi) p->slots[fi] = p->slots[p->sl_curr]; } } } if (was_busy) return -1; /* if good, now move it to the dst slab class */ p->slab_list[p->killing-1] = p->slab_list[p->slabs-1]; p->slabs--; p->killing = 0; dp->slab_list[dp->slabs++] = slab; dp->end_page_ptr = slab; dp->end_page_free = dp->perslab; /* this isn't too critical, but other parts of the code do asserts to make sure this field is always 0. */ for (iter=slab; iter<slab_end; iter+=dp->size) { ((item *)iter)->slabs_clsid = 0; } return 1; }