//item的具体结构 typedefstruct_stritem { //记录下一个item的地址,主要用于LRU链和freelist链 struct_stritem *next; //记录下一个item的地址,主要用于LRU链和freelist链 struct_stritem *prev; //记录HashTable的下一个Item的地址 struct_stritem *h_next; //最近访问的时间,只有set/add/replace等操作才会更新这个字段 //当执行flush命令的时候,需要用这个时间和执行flush命令的时间相比较,来判断是否失效 rel_time_t time; /* least recent access */ //缓存的过期时间。设置为0的时候,则永久有效。 //如果Memcached不能分配新的item的时候,设置为0的item也有可能被LRU淘汰 rel_time_t exptime; /* expire time */ //value数据大小 int nbytes; /* size of data */ //引用的次数。通过这个引用的次数,可以判断item是否被其它的线程在操作中。 //也可以通过refcount来判断当前的item是否可以被删除,只有refcount -1 = 0的时候才能被删除 unsignedshort refcount; uint8_t nsuffix; /* length of flags-and-length string */ uint8_t it_flags; /* ITEM_* above */ //slabs_class的ID。 uint8_t slabs_clsid;/* which slab class we're in */ uint8_t nkey; /* key length, w/terminating null and padding */ /* this odd type prevents type-punning issues when we do * the little shuffle to save space when not using CAS. */ //数据存储结构 union { uint64_t cas; char end; } data[]; /* if it_flags & ITEM_CAS we have 8 bytes CAS */ /* then null-terminated key */ /* then " flags length\r\n" (no terminating null) */ /* then data with terminating \r\n (no terminating null; it's binary!) */ } item;
//slabclass的结构 typedefstruct { //当前的slabclass存储最大多大的item unsignedint size; //每一个slab上可以存储多少个item.每个slab大小为1M, 可以存储的item个数根据size决定。 unsignedint perslab; //当前slabclass的(空闲item列表)freelist 的链表头部地址 //freelist的链表是通过item结构中的item->next和item->prev连建立链表结构关系 void *slots; /* list of item ptrs */ //当前总共剩余多少个空闲的item //当sl_curr=0的时候,说明已经没有空闲的item,需要分配一个新的slab(每个1M,可以切割成N多个Item结构) unsignedint sl_curr; /* total free items in list */ //总共分配多少个slabs unsignedint slabs; /* how many slabs were allocated for this class */ //分配的slab链表 void **slab_list; /* array of slab pointers */ unsignedint list_size; /* size of prev array */ unsignedint killing; /* index+1 of dying slab, or zero if none */ //总共请求的总bytes size_t requested; /* The number of requested bytes */ } slabclass_t; //定义一个slabclass数组,用于存储最大200个的slabclass_t的结构。 staticslabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];
//分配内存 staticvoidslabs_preallocate(constunsignedint maxslabs){ int i; unsignedint 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_t结构分配一个默认的slab for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) { if (++prealloc > maxslabs) return; 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); } } }
//分配一个Item staticvoid *do_slabs_alloc(constsize_t size, unsignedint id){ slabclass_t *p; void *ret = NULL; item *it = NULL; if (id < POWER_SMALLEST || id > power_largest) { MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); returnNULL; } //获取slabclass 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 说明是否有空闲的item list //如果没有空闲的item list,则取分配一个新的slab,如果分配失败,返回NULL if (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) { /* We don't have more memory available */ ret = NULL; //如果有free item lits,则从空闲的列表中取一个Item } elseif (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; }