/* Expand or create the hashtable */ int dictExpand(dict *d, unsigned long size) { dictht n; /* the new hashtable */ unsigned long realsize = _dictNextPower(size); /* the size is invalid if it is smaller than the number of * elements already inside the hashtable */ if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; /* Allocate the new hashtable and initialize all pointers to NULL */ n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(1, realsize*sizeof(dictEntry*)); n.used = 0; /* Is this the first initialization? If so it's not really a rehashing * we just set the first hash table so that it can accept keys. */ if (d->ht[0].table == NULL) { d->ht[0] = n; return DICT_OK; } /* Prepare a second hash table for incremental rehashing */ d->ht[1] = n; d->rehashidx = 0; return DICT_OK; }
//该函数会在真正创建哈希表或者扩展哈希表的时候被调用 int dictExpand(dict *d, unsigned long size) { dictht n; /* the new hash table */ //新的哈希表的bucket数目是大于当前used entry的数目的最小的2的指数 unsigned long realsize = _dictNextPower(size); /* the size is invalid if it is smaller than the number of * elements already inside the hash table */ //保证该字典未进行rehash,并且保证USED/BUCKETS的比率小于1 if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; /* Allocate the new hash table and initialize all pointers to NULL */ //分配并初始化一个新的哈希表 n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(realsize*sizeof(dictEntry*)); n.used = 0; /* Is this the first initialization? If so it's not really a rehashing * we just set the first hash table so that it can accept keys. */ //既然不是在rehash状态中,那么当前使用的哈希表应该是ht[0],如果它为NULL //说明这是在第一次分配该哈希表,所以将它保存在ht[0]中 if (d->ht[0].table == NULL) { d->ht[0] = n; return DICT_OK; } /* Prepare a second hash table for incremental rehashing */ //否则将新分配的哈希表保存在ht[1]中,因为不在rehash,所以当前ht[1]为空 //并且标记rehash标志,在接下来的哈希表操作中会进行rehash操作 d->ht[1] = n; d->rehashidx = 0; return DICT_OK; }
/* 对字典进行扩展 * * 这个函数完成以下两个工作的其中之一: * 1) 如果字典的 0 号哈希表不存在,那么创建它 * 2) 如果字典的 0 号哈希表存在,那么创建字典的 1 号哈希表 * * 这个函数的作用,对于第一件任务来说,是创建字典(的哈希表)。 * 而对于第二个任务来说,则是扩展字典(的哈希表)。 */ int dictExpand(dict *d, unsigned long size) { // 一般调用函数已经进行了检查,为了安全起见再次对参数进行检查 if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; // 计算哈希表的(真正)大小 unsigned long realsize = _dictNextPower(size); // 创建新哈希表 dictht n; n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(realsize*sizeof(dictEntry*)); n.used = 0; // 字典的 0 号哈希表是否已经初始化? // 如果没有的话,我们将新建哈希表作为字典的 0 号哈希表 if (d->ht[0].table == NULL) { d->ht[0] = n; } else { // 否则,将新建哈希表作为字典的 1 号哈希表,并将它用于 rehash d->ht[1] = n; d->rehashidx = 0; } return DICT_OK; }
/* Expand or create the hashtable */ static int dictExpand(dict *ht, unsigned long size) { dict n; /* the new hashtable */ unsigned long realsize = _dictNextPower(size), i; /* the size is invalid if it is smaller than the number of * elements already inside the hashtable */ if (ht->used > size) return DICT_ERR; _dictInit(&n, ht->type, ht->privdata); n.size = realsize; n.sizemask = realsize-1; n.table = calloc(realsize,sizeof(dictEntry*)); /* Copy all the elements from the old to the new table: * note that if the old hash table is empty ht->size is zero, * so dictExpand just creates an hash table. */ n.used = ht->used; for (i = 0; i < ht->size && ht->used > 0; i++) { dictEntry *he, *nextHe; if (ht->table[i] == NULL) continue; /* For each hash entry on this slot... */ he = ht->table[i]; while(he) { unsigned int h; nextHe = he->next; /* Get the new element index */ h = dictHashKey(ht, he->key) & n.sizemask; he->next = n.table[h]; n.table[h] = he; ht->used--; /* Pass to the next element */ he = nextHe; } } assert(ht->used == 0); free(ht->table); /* Remap the new hashtable in the old */ *ht = n; return DICT_OK; }