assoc动态扩容的条件:
现在的状态expanding是false,即没有进行扩容;并且item的个数大于hashsize(hashpower) 的1.5倍。
if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2)
几个变量的含义:
expand_bucket 表示现在正在移动桶的序号。
old_hashtable 原先hash表的指针。
primary_hashtable 新hash表的指针。
#define hashsize(n) ((ub4)1<<(n)) 计算桶的个数
#define hashmask(n) (hashsize(n)-1) 计算位置的掩码
hashpower hash表的级别,级别越高,空间越大,默认是16,通过hashsize(hashpower)计算桶的空间。
expanding 是否正在扩容中。
动态扩容的步骤:
1.首先启动assoc_maintenance_thread线程,如果此时未在同步,则阻塞在maintenance_cond条件变量处。
2.当条件满足时,设置assoc_start_expand为true,并唤醒maintenance_cond条件变量条件变量。
3.设置锁粒度为全局锁,并通知各个线程;
调用assoc_expand函数重新给primary_hashtable分配原先两倍的内存,设置expanding为true,hashpower++;
4.继续while循环,加全局锁和cache_lock锁,
从0开始,到hashsize(hashpower - 1)依次移动每一个桶。
对于每一个桶,通过hash(ITEM_key(it), it->nkey) & hashmask(hashpower)计算key在新的空间内的位置。
5.当满足移动完成退出条件expand_bucket == hashsize(hashpower - 1)时,
释放原先old_hashtable hash表的空间。
6.释放cache_lock和全局锁。
7.扩容完成继续阻塞在maintenance_cond处,等待下一次扩容时再唤醒。
发现了一处问题:
1.全程锁引起的效率问题思考?
当扩容的时候,通知其他线程锁粒度是全局的。开始扩容加的是全局锁,扩容完成才会释放全局锁。
也就是说在扩容的过程中,其他线程对应的增删查改都不能进行。
默认hashpower是16,即2^16=65536,可以容纳65536个元素,当大于65536*1.5的时候就需要扩容。
越到后边要移动的数据越多,不知会不会影响效率。
想到的解决办法:在传入参入的时候,设置hashpower的大小,设的较大一些,这边要扩容的可能性越小。
几处知识点:
pthread_getspecific pthread_setspecific函数