欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > 詳解Redis SCAN命令實現有限保證的原理

詳解Redis SCAN命令實現有限保證的原理

熱門標簽:400電話辦理的口碑 地圖標注工廠入駐 南京手機外呼系統廠家 臺灣電銷 高碑店市地圖標注app 一個地圖標注多少錢 b2b外呼系統 四川穩定外呼系統軟件 廊坊外呼系統在哪買

SCAN命令可以為用戶保證:從完整遍歷開始直到完整遍歷結束期間,一直存在于數據集內的所有元素都會被完整遍歷返回,但是同一個元素可能會被返回多次。如果一個元素是在迭代過程中被添加到數據集的,又或者是在迭代過程中從數據集中被刪除的,那么這個元素可能會被返回,也可能不會返回。

這是如何實現的呢,先從Redis中的字典dict開始。Redis的數據庫是使用dict作為底層實現的。

字典數據類型

Redis中的字典由dict.h/dict結構表示:

typedef struct dict {
 dictType *type;
 void *privdata;
 dictht ht[2];
 long rehashidx; /* rehashing not in progress if rehashidx == -1 */
 unsigned long iterators; /* number of iterators currently running */
} dict;

typedef struct dictht {
 dictEntry **table;
 unsigned long size;
 unsigned long sizemask;
 unsigned long used;
} dictht;

字典由兩個哈希表dictht構成,主要用做rehash,平常主要使用ht[0]哈希表。

哈希表由一個成員為dictEntry的數組構成,size屬性記錄了數組的大小,used屬性記錄了已有節點的數量,sizemask屬性的值等于size - 1。數組大小一般是2n,所以sizemask二進制是0b11111...,主要用作掩碼,和哈希值一起決定key應該放在數組的哪個位置。

求key在數組中的索引的計算方法如下:

index = hash d->ht[table].sizemask;

也就是根據掩碼求低位值。

rehash的問題

字典rehash時會使用兩個哈希表,首先為ht[1]分配空間,如果是擴展操作,ht[1]的大小為第一個大于等于2倍ht[0].used的2n,如果是收縮操作,ht[1]的大小為第一個大于等于ht[0].used的2n。然后將ht[0]的所有鍵值對rehash到ht[1]中,最后釋放ht[0],將ht[1]設置為ht[0],新創建一個空白哈希表當做ht[1]。rehash不是一次完成的,而是分多次、漸進式地完成。

舉個例子,現在將一個size為4的哈希表ht[0](sizemask為11, index = hash 0b11)rehash至一個size為8的哈希表ht[1](sizemask為111, index = hash 0b111)。

ht[0]中處于bucket0位置的key的哈希值低兩位為00,那么rehash至ht[1]時index取低三位可能為000(0)和100(4)。也就是ht[0]中bucket0中的元素rehash之后分散于ht[1]的bucket0與bucket4,以此類推,對應關系為:

 ht[0] -> ht[1]
 ----------------
  0 -> 0,4 
  1 -> 1,5
  2 -> 2,6
  3 -> 3,7

如果SCAN命令采取0->1->2->3的順序進行遍歷,就會出現如下問題:

•擴展操作中,如果返回游標1時正在進行rehash,ht[0]中的bucket0中的部分數據可能已經rehash到ht[1]中的bucket[0]或者bucket[4],在ht[1]中從bucket1開始遍歷,遍歷至bucket4時,其中的元素已經在ht[0]中的bucket0中遍歷過,這就產生了重復問題。
•縮小操作中,當返回游標5,但縮小后哈希表的size只有4,如何重置游標?

SCAN的遍歷順序

SCAN命令的遍歷順序,可以舉一個例子看一下:

127.0.0.1:6379[3]> keys *
1) "bar"
2) "qux"
3) "baz"
4) "foo"
127.0.0.1:6379[3]> scan 0 count 1
1) "2"
2) 1) "bar"
127.0.0.1:6379[3]> scan 2 count 1
1) "1"
2) 1) "foo"
127.0.0.1:6379[3]> scan 1 count 1
1) "3"
2) 1) "qux"
 2) "baz"
127.0.0.1:6379[3]> scan 3 count 1
1) "0"
2) (empty list or set)

可以看出順序是0->2->1->3,很難看出規律,轉換成二進制觀察一下:

00 -> 10 -> 01 -> 11

二進制就很明了了,遍歷采用的順序也是加法,但每次是高位加1的,也就是從左往右相加、從高到低進位的。

SCAN源碼

SCAN遍歷字典的源碼在dict.c/dictScan,分兩種情況,字典不在進行rehash或者正在進行rehash。

不在進行rehash時,游標是這樣計算的:

m0 = t0->sizemask;
// 將游標的umask位的bit都置為1
v |= ~m0;
// 反轉游標
v = rev(v);
// 反轉后+1,達到高位加1的效果
v++;
// 再次反轉復位
v = rev(v);

當size為4時,sizemask為3(00000011),游標計算過程:

   v |= ~m0 v = rev(v) v++  v = rev(v)
00000000(0) -> 11111100 -> 00111111 -> 01000000 -> 00000010(2)
00000010(2) -> 11111110 -> 01111111 -> 10000000 -> 00000001(1)
00000001(1) -> 11111101 -> 10111111 -> 11000000 -> 00000011(3)
00000011(3) -> 11111111 -> 11111111 -> 00000000 -> 00000000(0)

遍歷size為4時的游標狀態轉移為0->2->1->3。

同理,size為8時的游標狀態轉移為0->4->2->6->1->5->3->7,也就是000->100->010->110->001->101->011->111。

再結合前面的rehash:

  ht[0] -> ht[1]
  ----------------
   0  ->  0,4 
   1  ->  1,5
   2  ->  2,6
   3  ->  3,7

可以看出,當size由小變大時,所有原來的游標都能在大的哈希表中找到相應的位置,并且順序一致,不會重復讀取并且不會遺漏。

當size由大變小的情況,假設size由8變為了4,分兩種情況,一種是游標為0,2,1,3中的一種,此時繼續讀取,也不會遺漏和重復。

但如果游標返回的不是這四種,例如返回了7,711之后變為了3,所以會從size為4的哈希表的bucket3開始繼續遍歷,而bucket3包含了size為8的哈希表中的bucket3與bucket7,所以會造成重復讀取size為8的哈希表中的bucket3的情況。

所以,redis里rehash從小到大時,SCAN命令不會重復也不會遺漏。而從大到小時,有可能會造成重復但不會遺漏。

當正在進行rehash時,游標計算過程:

  /* Make sure t0 is the smaller and t1 is the bigger table */
    if (t0->size > t1->size) {
      t0 = d->ht[1];
      t1 = d->ht[0];
    }
    m0 = t0->sizemask;
    m1 = t1->sizemask;
    /* Emit entries at cursor */
    if (bucketfn) bucketfn(privdata, t0->table[v  m0]);
    de = t0->table[v  m0];
    while (de) {
      next = de->next;
      fn(privdata, de);
      de = next;
    }
    /* Iterate over indices in larger table that are the expansion
     * of the index pointed to by the cursor in the smaller table */
    do {
      /* Emit entries at cursor */
      if (bucketfn) bucketfn(privdata, t1->table[v  m1]);
      de = t1->table[v  m1];
      while (de) {
        next = de->next;
        fn(privdata, de);
        de = next;
      }
      /* Increment the reverse cursor not covered by the smaller mask.*/
      v |= ~m1;
      v = rev(v);
      v++;
      v = rev(v);
      /* Continue while bits covered by mask difference is non-zero */
    } while (v  (m0 ^ m1));

算法會保證t0是較小的哈希表,不是的話t0與t1互換,先遍歷t0中游標所在的bucket,然后再遍歷較大的t1。

求下一個游標的過程基本相同,只是把m0換成了rehash之后的哈希表的m1,同時還加了一個判斷條件:

v (m0 ^ m1)

size4的m0為00000011,size8的m1為00000111,m0 ^ m1取值為00000100,即取二者mask的不同位,看游標在這些標志位是否為1。

假設游標返回了2,并且正在進行rehash,此時size由4變成了8,二者mask的不同位是低第三位。

首先遍歷t0中的bucket2,然后遍歷t1中的bucket2,公式計算出的下一個游標為6(00000110),低第三位為1,繼續循環,遍歷t1中的bucket6,然后計算游標為1,結束循環。

所以正在rehash時,是兩個哈希表都遍歷的,以避免遺漏的情況。

總結

以上所述是小編給大家介紹的Redis SCAN命令實現有限保證的原理,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

您可能感興趣的文章:
  • Redis中scan命令的深入講解
  • php redis擴展支持scan命令實現方法
  • Redis中Scan命令的基本使用教程
  • Redis Scan命令的基本使用方法
  • Redis中Scan命令的踩坑實錄
  • redis中scan命令的基本實現方法

標簽:南寧 泰州 定州 拉薩 畢節 甘南 河源 伊春

巨人網絡通訊聲明:本文標題《詳解Redis SCAN命令實現有限保證的原理》,本文關鍵詞  詳解,Redis,SCAN,命令,實現,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《詳解Redis SCAN命令實現有限保證的原理》相關的同類信息!
  • 本頁收集關于詳解Redis SCAN命令實現有限保證的原理的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    国产日韩精品中文字无码| 午夜精品福利在线视频| 蜜臂av日日欢夜夜爽一区| 亚洲午夜免费视频| 国产成人99久久亚洲综合精品| 亚洲午夜久久久久久久久红桃 | 国产裸体歌舞团一区二区| 国精品无码人妻一区二区三区| 91麻豆精品国产91久久久使用方法| 一区二区免费视频| 国模大尺度视频| 欧美亚洲丝袜传媒另类| 亚洲美女视频一区| 91麻豆国产自产在线观看| 日本丰满少妇一区二区三区| 亚洲欧美日韩电影| 中文字幕人妻无码系列第三区| 精品视频色一区| 婷婷综合另类小说色区| 亚洲久久久久久| 亚洲精品在线观看网站| 极品少妇一区二区三区精品视频| www.中文字幕av| 久久精品一区二区三区不卡牛牛| 国产精品亚洲一区二区三区在线| 美国黄色特级片| 国产精品久久久久7777按摩| av亚洲精华国产精华精华| 在线观看亚洲精品| 日日噜噜夜夜狠狠视频欧美人 | 亚洲午夜激情网页| 亚洲视频在线播放免费| 日韩免费视频一区二区| 国产一区二区三区精品欧美日韩一区二区三区| 夫妇交换中文字幕| 亚洲欧美自拍偷拍| 性活交片大全免费看| 欧美成人国产一区二区| 国产中文字幕一区| 永久免费看片视频教学| 亚洲免费看黄网站| 成人免费无码大片a毛片| 欧美精品一区二区三区很污很色的| 国产精品888| 欧美综合亚洲图片综合区| 亚洲va欧美va天堂v国产综合| 亚洲最大成人网站| 国产精品色眯眯| 欧美综合久久久| 婷婷中文字幕综合| eeuss中文字幕| 亚洲精品国产一区二区精华液| 艳妇乳肉豪妇荡乳xxx| 久久精品在这里| 4438x全国最大成人| 欧美一区二区三区喷汁尤物| 国产美女精品一区二区三区| 欧美亚日韩国产aⅴ精品中极品| 日本成人在线网站| 青青草原在线免费观看| 日韩精品一级二级| 乱h高h女3p含苞待放| 婷婷中文字幕一区三区| 精品国产视频一区二区三区| 天天综合色天天综合色h| 东京热无码av男人的天堂| 一区二区不卡在线播放| 国产伦精品一区二区三区视频女| 亚洲精品视频免费观看| 麻豆精品免费视频| 一区二区三区日本| 国产成人精品视频免费| 亚洲超丰满肉感bbw| 欧美h片在线观看| 日韩精品一卡二卡三卡四卡无卡 | 免费在线观看一区| 老熟妇高潮一区二区三区| 天堂成人国产精品一区| 全程偷拍露脸中年夫妇| 麻豆国产精品777777在线| 91国内精品野花午夜精品 | 日韩不卡一二三区| 色综合久久中文综合久久97 | 欧美性视频一区二区三区| 激情综合色播激情啊| 欧美日韩二区三区| 成人av电影在线观看| 亚洲精品一区在线观看| 国产香蕉精品视频| 国产精品成人免费| 欧美精品日韩在线| 日韩高清中文字幕一区| 在线观看日韩电影| 成人一区二区三区视频| 久久影音资源网| 91美女片黄在线观看91美女| 欧美国产欧美综合| a毛片毛片av永久免费| 亚洲成人tv网| 欧美亚洲国产怡红院影院| 国产精品亚洲一区二区三区妖精| 中文字幕第10页| 少妇av片在线观看| 日韩1区2区3区| 欧美日韩在线播放三区四区| 不卡一区中文字幕| 国产精品免费网站在线观看| 久久亚洲无码视频| 蜜臀国产一区二区三区在线播放| 欧美挠脚心视频网站| 91影院在线观看| 国产精品欧美一区喷水| 久久日免费视频| 极品销魂美女一区二区三区| 日韩精品一区二区三区老鸭窝| 911亚洲精选| 香蕉加勒比综合久久| 欧美三级三级三级| av地址在线观看| 亚洲精品欧美专区| 91精彩视频在线观看| 99久久夜色精品国产网站| 中文字幕的久久| 我要看黄色一级片| 国产精品一区一区| 中文字幕欧美区| 91免费公开视频| 成人午夜激情片| 一色屋精品亚洲香蕉网站| 全网免费在线播放视频入口| 高清免费成人av| 中文字幕中文字幕一区二区| 精品人妻伦九区久久aaa片| 成人午夜在线播放| 亚洲视频一区二区免费在线观看| 午夜69成人做爰视频| 91在线国产观看| 亚洲综合在线第一页| 欧美美女直播网站| 国产成人精品无码片区在线| 石原莉奈一区二区三区在线观看| 欧美一区二区网站| 好吊视频在线观看| 国产一区二区三区日韩| 国产精品久久久久久久蜜臀 | 99久久伊人久久99| 亚洲小说欧美激情另类| 91精品国产全国免费观看 | 亚洲图片欧美色图| 91精品国产综合久久久久久久| 国产精品九九九九九| 蜜乳av一区二区| 亚洲国产精品激情在线观看| 国产这里有精品| 丰满少妇中文字幕| 免费人成在线不卡| 国产日本一区二区| 国产精品中文字幕日韩精品| 欧美性猛交xxxxxx富婆| 中文字幕一区三区久久女搜查官| 久久99国产精品成人| 中文久久乱码一区二区| 在线观看视频一区二区| 国产精品久久无码| 国产精品69久久久久水密桃| 亚洲丝袜另类动漫二区| 欧美日韩精品一区二区在线播放| 欧美大片免费播放器| 国产剧情一区二区| 一区二区免费在线| 精品国产青草久久久久福利| 天天色天天综合| 91丨国产丨九色丨pron| 天堂蜜桃一区二区三区| 久久久久国产精品人| 91高清在线观看| 六月婷婷七月丁香| 99在线精品观看| 日韩黄色小视频| 国产精品久久久久影院老司| 欧美挠脚心视频网站| 亚洲精品一区二区三区影院忠贞| eeuss国产一区二区三区| 亚洲国产视频一区| 久久久久国产精品免费免费搜索| 欧美综合天天夜夜久久| 中文字幕欧美激情极品| 日本少妇一区二区三区| 久久se精品一区精品二区| 亚洲天堂网中文字| 精品福利在线导航| 欧美体内she精视频| 国产传媒在线看| 秘密基地免费观看完整版中文 | 免费观看成人av| 综合中文字幕亚洲| 精品区一区二区| 欧美午夜免费电影| 国产视频精品免费| 日本黄色特级片|