memcached缓存命中机制与PostgreSQL非常相似,都是对数据缓存进行分区,根据哈希码在对应分区内匹配键值。不同的是PG分区使用常数(早先为16、9.5开始改为128,可以支持更大缓存),分区数量较少;而memcached根据线程数确定初始分区数,数量相对较大,并且有后台维护程序动态管理。
分区数量确定,在线程初始化部分,thread.c中函数thread_init:
/* Want a wide lock table, but don't waste memory */
if (nthreads < 3) {
power = 10;
} else if (nthreads < 4) {
power = 11;
} else if (nthreads < 5) {
power = 12;
} else {
/* 8192 buckets, and central locks don't scale much past 5 threads */
power = 13;
}
item_lock_count = hashsize(power);
item_lock_hashpower = power;
默认线程数为4,hashpower为12。
thread.c中的store_item函数,以键值计算哈希码:
hv = hash(ITEM_key(item), item->nkey);
while (it) {
if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
ret = it;
break;
}
it = it->h_next;
++depth;
}
分区扩展机制,:
/* We are done expanding.. just wait for next invocation */
mutex_lock(&cache_lock);
started_expanding = false;
pthread_cond_wait(&maintenance_cond, &cache_lock);
/* Before doing anything, tell threads to use a global lock */
mutex_unlock(&cache_lock);
slabs_rebalancer_pause();
switch_item_lock_type(ITEM_LOCK_GLOBAL);
mutex_lock(&cache_lock);
assoc_expand();
mutex_unlock(&cache_lock);
这是后台维护线程的部分代码,当条目数达到临界值(hashsize(hashpower) * 3) / 2)时触发maintenance_cond,条件触发在assoc.c中的assoc_start_expand函数中。