Redis內部資料結構詳解之字典(dict)
阿新 • • 發佈:2019-01-29
/* Expand or create the hash table */ int dictExpand(dict *d, unsigned long size) { dictht n; /* the new hash table */ unsigned long realsize = _dictNextPower(size); //得到需要擴充套件到的size /* the size is invalid if it is smaller than the number of * elements already inside the hash table */ 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. */ if (d->ht[0].table == NULL) { d->ht[0] = n; return DICT_OK; } /* Prepare a second hash table for incremental rehashing */ //準備漸進式rehash,rehash的字典table為0號 d->ht[1] = n; d->rehashidx = 0; return DICT_OK; } /* Expand the hash table if needed */ static int _dictExpandIfNeeded(dict *d) { /* Incremental rehashing already in progress. Return. */ if (dictIsRehashing(d)) return DICT_OK; // 如果雜湊表為空,那麼將它擴充套件為初始大小 if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); /*如果雜湊表的已用節點數 >= 雜湊表的大小,並且以下條件任一個為真: 1) dict_can_resize 為真 2) 已用節點數除以雜湊表大小之比大於 dict_force_resize_ratio 那麼呼叫 dictExpand 對雜湊表進行擴充套件,擴充套件的體積至少為已使用節點數的兩倍 */ if (d->ht[0].used >= d->ht[0].size && (dict_can_resize || d->ht[0].used/d->ht[0].size > dict_force_resize_ratio)) { return dictExpand(d, d->ht[0].used*2); } return DICT_OK; } static int _dictKeyIndex(dict *d, const void *key) { unsigned int h, idx, table; dictEntry *he; /* Expand the hash table if needed */ if (_dictExpandIfNeeded(d) == DICT_ERR) return -1; /* Compute the key hash value */ h = dictHashKey(d, key);//通過hash函式得到key所在的bucket索引位置 //查詢在現有字典中是否出現了該key for (table = 0; table <= 1; table++) { idx = h & d->ht[table].sizemask; /* Search if this slot does not already contain the given key */ he = d->ht[table].table[idx]; while(he) { if (dictCompareKeys(d, key, he->key)) return -1; he = he->next; } //如果系統沒在rehash則不需要查詢ht[1] if (!dictIsRehashing(d)) break; } return idx; } dictEntry *dictAddRaw(dict *d, void *key) { int index; dictEntry *entry; dictht *ht; if (dictIsRehashing(d)) _dictRehashStep(d);// 嘗試漸進式地 rehash 桶中一組元素 /* Get the index of the new element, or -1 if * the element already exists. */ // 查詢可容納新元素的索引位置,如果元素已存在, index 為 -1 if ((index = _dictKeyIndex(d, key)) == -1) return NULL; /* Allocate the memory and store the new entry */ ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0]; // 決定該把新元素放在那個雜湊表 entry = zmalloc(sizeof(*entry)); //頭插法,插入節點 entry->next = ht->table[index]; ht->table[index] = entry; ht->used++; /* Set the hash entry fields. */ dictSetKey(d, entry, key);//關聯起key return entry; } /* Add an element to the target hash table */ //新增一個元素 int dictAdd(dict *d, void *key, void *val) { dictEntry *entry = dictAddRaw(d,key); if (!entry) return DICT_ERR; dictSetVal(d, entry, val);//關聯起value return DICT_OK; }