±¾ÎÄËùÒýÓõÄÔ´ÂëÈ«²¿À´×ÔRedis2.8.2°æ±¾¡£
RedisÖÐ×ÖµädictÊý¾Ý½á¹¹ÓëAPIÏà¹ØÎļþÊÇ£ºdict.h, dict.c¡£
±¾ÎĽ²½âµÄ²»ÊǺÜÏêϸ£¬¿ÉÒÔͬʱ²Î¿¼RedisʵÏÖÓëÉè¼ÆÒ»ÊéÖÐ×ֵ䲿·Ö£¬±¾ÎĹØÓÚ×ÖµäµÄºËÐÄ´úÂëµÄ×¢ÊÍ¿ÉÒԲο¼¡£
×ֵ䣬¼òµ¥Ëµ¾ÍÊÇ´æ´¢key-value¼üÖµÊý¾Ý£¬µ±È»value=NULLÄÇô¾ÍÊǼ¯ºÏÁË¡£×ÖµäͨË×À´Ëµ¾ÍÊÇC++
STLÖеÄmap£¬STLÖеÄmapÊÇÓÃred-black treeʵÏֵģ¬ÒòΪmap²»½öÄܹ»±£Ö¤key²»Öظ´£¬¶øÇÒkey»¹Êǰ´ÕÕ×ÖµäÐò´æ´¢µÄ£¬¶øRedisÖеÄ×ֵ䲢²»ÒªÇóÓÐÐò£¬Òò´ËΪÁ˽µµÍ±àÂëµÄÄѶÈʹÓùþÏ£±í×÷Ϊ×ÖµäµÄµ×²ãʵÏÖ¡£RedisµÄ×ÖµäÊÇʹÓÃÒ»¸öͰbucket£¬Í¨¹ý¶Ôkey½øÐÐhashµÃµ½µÄË÷ÒýÖµindex£¬È»ºó½«key-valueµÄÊý¾Ý´æÔÚͰµÄindexλÖã¬Redis´¦ÀíhashÅöײµÄ·½Ê½ÊÇÁ´±í£¬Á½¸ö²»Í¬µÄkey
hashµÃµ½ÏàͬµÄË÷ÒýÖµ£¬ÄÇô¾ÍʹÓÃÁ´±í½â¾ö³åÍ»¡£Ê¹ÓÃÁ´±í×ÔÈ»µ±´æ´¢µÄÊý¾Ý¾Þ´óµÄʱºò£¬×ֵ䲻Ãâ»áÍË»¯³É¶à¸öÁ´±í£¬Ð§ÂÊ´ó´ó½µµÍ£¬Redis²ÉÓÃrehashµÄ·½Ê½¶ÔͰ½øÐÐÀ©ÈÝÀ´½â¾öÕâÖÖÍË»¯¡£
RedisʹÓõÄhashËã·¨ÓÐÒÔÏÂÁ½ÖÖ£º
1. MurmurHash2 32 bit Ëã·¨£ºÕâÖÖËã·¨µÄ·Ö²¼ÂʺÍËٶȶ¼·Ç³£ºÃ£¬¾ßÌåÐÅÏ¢Çë²Î¿¼
MurmurHash µÄÖ÷Ò³£ºhttp://code.google.com/p/smhasher/ ¡£
2. »ù ÓÚ djb Ëã ·¨ ʵ ÏÖ µÄ Ò» ¸ö ´ó С д ÎÞ ¹Ø É¢
ÁÐ Ëã ·¨£º ¾ß Ìå ЊϢ Çë ²Î ¿¼
http://www.cse.yorku.ca/~oz/hash.html ¡£
×ÖµäÊý¾Ý½á¹¹
typedef struct dictEntry {//×ÖµäµÄ½Úµã void *key; union {//ʹÓõÄÁªºÏÌå void *val; uint64_t u64;//ÕâÁ½¸ö²ÎÊýºÜÓÐÓà int64_t s64; } v; struct dictEntry *next;//ÏÂÒ»¸ö½ÚµãÖ¸Õë } dictEntry; typedef struct dictType { unsigned int (*hashFunction)(const void *key); //hashº¯ÊýÖ¸Õë void *(*keyDup)(void *privdata, const void *key); //¼ü¸´Öƺ¯ÊýÖ¸Õë void *(*valDup)(void *privdata, const void *obj); //Öµ¸´Öƺ¯ÊýÖ¸Õë int (*keyCompare)(void *privdata, const void *key1, const void *key2); //¼ü±È½Ïº¯ÊýÖ¸Õë void (*keyDestructor)(void *privdata, void *key); //¼ü¹¹Ô캯ÊýÖ¸Õë void (*valDestructor)(void *privdata, void *obj); //Öµ¹¹Ô캯ÊýÖ¸Õë } dictType; /* This is our hash table structure. Every dictionary has two of this as we * implement incremental rehashing, for the old to the new table. */ typedef struct dictht { //×Öµähash table dictEntry **table;//¿ÉÒÔ¿´×ö×ÖµäÊý×飬Ë׳ÆÍ°bucket unsigned long size; //Ö¸ÕëÊý×éµÄ´óС£¬¼´Í°µÄ²ãÊý unsigned long sizemask; unsigned long used; //×ÖµäÖе±Ç°µÄ½ÚµãÊýÄ¿ } dictht; typedef struct dict { dictType *type; void *privdata; //˽ÓÐÊý¾Ý dictht ht[2]; //Á½¸öhash table int rehashidx; /* rehashing not in progress if rehashidx == -1 */ //rehash Ë÷Òý int iterators; /* number of iterators currently running */ //µ±Ç°¸Ã×Öµäµü´úÆ÷¸öÊý } dict; |
dictÊý¾Ý½á¹¹ÖÐÉùÃ÷ÁËÁ½¸ö×Öµähashtable½á¹¹dictht£¬ht[1]ÔÚrehashʱºòʹÓ㬺óÃæ¾ßÌå·ÖÎö¡£
ÏÂͼ¸ø³öÕû¸ö×Öµä½á¹¹£¬Í¼Æ¬À´×ÔRedisÉè¼ÆÓëʵÏÖÒ»Ê飺

ÉÏͼht[1]Ϊ¿Õ£¬ËµÃ÷µ±È»×ÖµäûÔÚRehash״̬¡£
×ÖµäµÄAPIº¯Êý

´´½¨ÐÂ×Öµä
ͨ¹ýdictCreateº¯Êý´´½¨Ò»¸öÐÂ×Öµädict *dictCreate(dictType
*type, void *privDataPtr)£¬Ò»¸ö¿Õ×ÖµäµÄʾÒâͼÈçÏÂ(ͼƬÀ´×ÔRedisÉè¼ÆÓëʵÏÖÒ»Êé):

ÉÏÃæÒѾÌáÆð¹ý£¬ht[1]Ö»ÔÚRehashʱʹÓá£
×ÖµäÌí¼ÓÔªËØ
¸ù¾Ý×ֵ䵱ǰµÄ״̬£¬½«Ò»¸ökey-valueÔªËØÌí¼Óµ½×ÖµäÖпÉÄÜ»áÒýÆðһϵÁи´ÖƵIJÙ×÷£º
Èç¹û×Öµäδ³õʼ»¯£¨¼´×ÖµäµÄ0ºÅ¹þÏ£±íht[0]µÄtableΪ¿Õ£©£¬ÄÇôÐèÒªµ÷ÓÃdictExpandº¯Êý¶ÔËü³õʼ»¯£»
Èç¹û²åÈëµÄÔªËØkeyÒѾ´æÔÚ£¬ÄÇôÌí¼ÓÔªËØÊ§°Ü£»
Èç¹û²åÈëÔªËØÊ±£¬ÒýÆðÅöײ£¬ÐèҪʹÓÃÁ´±íÀ´´¦ÀíÅöײ£»
Èç¹û²åÈëÔªËØÊ±£¬ÒýÆð³ÌÐòÂú×ãRehashµÄÌõ¼þʱ£¬Ïȵ÷ÓÃdictExpandº¯ÊýÀ©Õ¹¹þÏ£±íµÄsize£¬È»ºó×¼±¸½¥½øÊ½Rehash²Ù×÷¡£
×ÖµäÌí¼ÓÔªËØµÄÁ÷³Ìͼ£¬À´×ÔRedisÉè¼ÆÓëʵÏÖÒ»Êé

/* 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; } |
×ÖµäRehash½âÎö
RehashµÄ´¥·¢»úÖÆ£ºµ±Ã¿´ÎÌí¼ÓÐÂÔªËØÊ±£¬¶¼»á¶Ô¹¤×÷¹þÏ£±íht[0]½øÐмì²é£¬Èç¹ûused£¨¹þÏ£±íÖÐÔªËØµÄÊýÄ¿£©Óësize£¨Í°µÄ´óС£©±ÈÂÊratioÂú×ãÒÔÏÂÈÎÒ»Ìõ¼þ£¬½«¼¤»î×ÖµäµÄRehash»úÖÆ£ºratio=used
/ size£¬ ratio >= 1²¢ÇÒdict_can_resize ÎªÕæ£»ratio ´ó ÓÚ
±ä Á¿ dict_force_resize_ratio ¡£
RehashÖ´Ðйý³Ì£º
´´½¨Ò»¸ö±Èht[0].usedÖÁÉÙÁ½±¶µÄht[1].table£»½«Ôht[0].tableÖÐËùÓÐÔªËØÇ¨ÒÆµ½ht[1].table£»Çå¿ÕÔÀ´ht[0]£¬½«ht[1]Ìæ»»³Éht[0]
½¥½øÊ½RehashÖ÷ÒªÓÉÁ½¸öº¯ÊýÀ´½øÐУº
_dictRehashStep:µ±¶Ô×ֵ佸ÐÐÌí¼Ó¡¢²éÕÒ¡¢É¾³ý¡¢Ëæ»ú»ñÈ¡ÔªËØ¶¼»áÖ´ÐÐÒ»´Î£¬Æäÿ´ÎÔÚ¿ªÊ¼Rehashºó£¬½«ht[0].tableµÄµÚÒ»¸ö²»Îª¿ÕµÄË÷ÒýÉϵÄËùÓнڵãÈ«²¿Ç¨ÒƵ½ht[1].table;
dictRehashMilliseconds:ÓÉRedis·þÎñÆ÷³£¹æÈÎÎñ³ÌÐò(serverCron)Ö´ÐУ¬ÒÔºÁÃëΪµ¥Î»£¬ÔÚÒ»¶¨Ê±¼äÄÚ£¬ÒÔÿ´ÎÖ´ÐÐ100²½rehash²Ù×÷¡£
Rehash²Ù×÷ºËÐĺ¯Êý£º
int dictRehash(dict *d, int n) { if (!dictIsRehashing(d)) return 0; while(n--) { dictEntry *de, *nextde; /* Check if we already rehashed the whole table... */ if (d->ht[0].used == 0) {//ÒѾÍê³É zfree(d->ht[0].table);//ÊÍ·Åht[0].table d->ht[0] = d->ht[1]; //ÕâÀïht[0]Óëht[1]¶¼²»ÊÇÖ¸Õ룬ֱ½Ó¸³Öµ¾ÍÌæ»»ÁË _dictReset(&d->ht[1]);//½«ht[1].tableÉèÖÃΪnull d->rehashidx = -1; return 0; } /* Note that rehashidx can't overflow as we are sure there are more * elements because ht[0].used != 0 */ assert(d->ht[0].size > (unsigned)d->rehashidx); //ÕÒµ½µÚÒ»¸ö²»Îª¿ÕµÄÊý×é while(d->ht[0].table[d->rehashidx] == NULL) d->rehashidx++; //Ö¸Ïò¸ÃÁ´±íÍ· de = d->ht[0].table[d->rehashidx]; /* Move all the keys in this bucket from the old to the new hash HT */ while(de) {//±éÀúÁ´±í unsigned int h; nextde = de->next; /* Get the index in the new hash table */ //µÃµ½ÔÚht[1]ÖеÄË÷ÒýºÅ£¬Í¨¹ýÏàÓ¦µÄhashº¯Êý h = dictHashKey(d, de->key) & d->ht[1].sizemask; // Ìí¼Ó½Úµãµ½ ht[1] £¬µ÷ÕûÖ¸Õ룬²ÉÓõÄÊÇÍ·²å·¨ de->next = d->ht[1].table[h]; d->ht[1].table[h] = de; d->ht[0].used--; d->ht[1].used++; de = nextde; } d->ht[0].table[d->rehashidx] = NULL;//ÉèÖÃΪ¿Õ d->rehashidx++; } return 1; } |
С½á
RedisÖеÄ×ÖµäÊý¾Ý½á¹¹Ê¹ÓùþÏ£±íÀ´ÊµÏÖ£¬ÓÃÀ´´æ´¢key-value¼üÖµÔªËØ£»
×ÖµäʹÓÃÁ½¸ö¹þÏ£±í£¬Ò»°ãֻʹÓÃht[0]£¬Ö»Óе±Rehashʱºò²ÅʹÓÃht[0]£»
¹þÏ£±í²ÉÓÃÁ´±íµÄ·½Ê½½â¾ö¼üÅöײÎÊÌ⣻
RedisµÄRehash²Ù×÷Êǽ¥½øÊ½µÄ£¬·þÎñÆ÷³ÌÐò»áÖ÷¶¯Rehash£¬ÔÚ²éÕÒ¡¢Ìí¼Ó¡¢É¾³ýÔªËØµÈ²Ù×÷ʱҲ»áÔÚRehash½øÐÐʱִÐÐÒ»´Îrehash²Ù×÷¡£
×ÖµäµÄÄÚÈÝʵÔÚÌ«¶à£¬²Ù×÷±È½Ï·±Ëö£¬Ó¦¸ÃÊÇRedisÖÐ×ÔӵĵײãÊý¾Ý½á¹¹ÁË£¬±¾ÎÄ·ÖÎöµÄ¾ø¶Ô²»¹»ÉîÈ룬ϣÍûÒÔºóÓÐʱ¼äÔÙÐ޸İɣ¬ÔÝʱÏÈÕâÑù¡£µ½Ä¿Ç°ÎªÖ¹£¬RedisÁùÖÖÄÚ²¿Êý¾Ý½á¹¹£¬Í¬Ê±Ò²Êǵײã²Ù×÷µÄʵÏÖ½²½âÈ«²¿½áÊø£¬ºóÃæµÄÎÄÕ½«½øÈëÎåÖÖ»ù±¾Êý¾ÝÀàÐÍÖ¸ÁîµÄʵÏÖ£¬×Ö·û´®£¨String£©¡¢¹þÏ£±í£¨Hash£©¡¢ÁÐ±í£¨List£©¡¢¼¯ºÏ£¨Set£©¡¢ÓÐÐò¼¯ºÏ£¨Sorted
Set£©µÄ¸÷ÖÖÖ¸ÁîµÄʵÏÖ¡£
ÎÒ×Ô¼º¶ÔRedis2.8.2Ô´ÂëµÄ×¢ÊÍ£¬ÓÐʱ¼äÕÒ¸ö»ú»á·Å³öÀ´¡£
×îºó¸Ðл»Æ½¡ºê£¨huangz1990£©µÄRedisÉè¼ÆÓëʵÏÖ¼°ÆäËû¶ÔRedis2.6Ô´ÂëµÄÏà¹Ø×¢ÊͶÔÎÒÔÚÑо¿Redis2.8Ô´Âë·½ÃæµÄ°ïÖú¡£
|