日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis的设计与实现之整数集合和压缩列表

發布時間:2024/4/18 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis的设计与实现之整数集合和压缩列表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

整數集合(intset)

整數集合概念

  • 整數集合是一個集合(set)
  • 整數集合里只包含整數,并且集合元素不能太多
  • 整數集合不會有重復的元素(有重復元素集合就沒意義了)

整數集合的實現方式

typedef struct intest{//編碼方式uint32_t encoding;//包含元素的數量uint32_t length;//保存元素的數組int8_t contents[]; }intest
  • encoding : 保存編碼方式
  • length : 保存元素的數量(數組的元素個數)
  • contents : 保存set里的元素,數組里的元素按從小到大有序排列

那么在整數集合怎么保證它的有序性?

它根據的是數組的插入排序,先確定好位置,然后插進去,后邊的元素后移。

在整數集合中可以保存int_16,int_32,int_64的整數

那在整數集合中怎樣處理這幾種整數類型之間的關系呢?假設數組中的最大值為x。

  • -32768(-2e15) < x < 32761((2e15)-1) : 那么它就是用int_16的編碼方式
  • -2147483648(-2e31) < x < 2147483647((2e31)-1) : 那么它就是用的int_32的編碼方式
  • -9223372036854775808(-2e63) < x < 9223372036854775807((2e63)-1) : 那么它就使用int_64的編碼方式

那如果我在集合中加了超過此編碼方式的極限呢?比如:本來是16位,但是我要存100000,因此就有了下邊的升級操作了。

升級

當我們要添加一個新元素并且新元素的值大于或小于當前的所能存取值的極限,因此,在存之前內部要對整數集合進行升級,然后將我們的值存進去。

升級的步驟:

  • 根據新元素類型,擴展空間,并為新元素分配空間
  • 將其余數也換位該元素類型,并維持底層有序性
  • 將新元素加到數組里
  • 升級的好處:

  • 節約空間
  • 提升整數集合的靈活性(隨意添加元素不怕類型有誤,內部會自動轉類型)
  • 那升級了,然后我把超出極限的元素移出來了,是不是能降級了?

    整數集合不支持降級操作,升級后就一直保存這種編碼方式,除非再次升級。就和我們玩的象棋里的士兵一樣。

    壓縮列表(ziplist)

    壓縮列表的概念

    • Redis為節約內存而開發的,由一系列特殊編碼的連續內存塊組成的順序型(sequential)數據結構。
    • 在Redis里被用作哈希鍵的底層實現之一:當列表鍵只包含少量的列表項,并且每個列表項都要是小整數或者是短字符串。
    • 由多個節點(entry)組成,每個節點保存一個字節數組(字符串)或者一個整數。

    壓縮列表的實現方式

    struct ziplist<T> {// 整個壓縮列表占用字節數int32 zlbytes; // 最后一個元素距離壓縮列表起始位置的偏移量,用于快速定位到最后一個節點int32 zltail_offset; //元素個數,鍵值對的個數,也就的T的長度int16 zllen; //鍵值對,順序存儲T[] entries; // 標志壓縮列表的結束,值恒為 0xFFint8 zlend; }
    • zlbytes : 記錄整個壓縮列表占的字節數:在內存重分配或者計算zlend時使用
    • zltail_offset : 通過偏移量可以很方便的找到尾節點
    • zllen : 記錄節點數量,如果數量超過或等于65535(zllen占用2個字節)時需要遍歷整個壓縮列表才能得出。
    • entries : 保存節點內容
    • zlend : 是一個常量標志結束。

    壓縮列表節點的實現方式

    struct entry {// 前一個 entry 的字節長度int<var> previous_entry_length;//元素的編碼int<var> encoding; //內容optional byte[] content;}
    • previous_entry_length : 保存前一個節點長度,長度可以為1個字節或5個字節。

    • 1個字節 : 在這個字節里就保存前一個節點的長度(小于254)
    • 5個字節 : 當前一個節點的長度大于等于254,那就采用五個字節。前一個字節為固定的OxFE(254),后四個字節存
      儲前一個節點的長度。比如:OxFE00002768 表示的是Ox00002766(十進制是10088)
    • encoding : 記錄的是content屬性中保存的類型和長度。

    • 如果是字節數組,encoding可以是一字節,兩字節,五字節分別以00,01,10打頭。

    • 如果是整數,那就是一個字節以11打頭。

    • content : 保存節點的內容

    連鎖更新問題

    那如果由一個這樣的情況 : 在壓縮列表由多個長度介于250-253的節點,我們要在表頭節點插入一個新的節點(比較大的),但是它后一個節點的previous_entry_length用一個字節保存不了,因此它會采用五個字節來保存,因此新節點的后一個節點占用的字節數就增多為254以上,然后又很巧合這個節點的下一個節點長度也是介于250-253,然后它也增多為254以上,然后導致它后邊節點的字節變化。這個就是連鎖更新問題。程序需要對壓縮列表不斷的進行重分配操作。

    當然,上邊的情況只是連鎖更新的一種,刪除節點也同樣會發生連鎖更新問題。

    比如是在一個small節點(小于254),它的前邊是一個big節點(大于254),然后在small節點后都是介于250-253大小的節點,當我們刪除small節點時,就會引起后邊節點的存儲空間變化,也同樣會導致連鎖更新。

    那連鎖更新會不會讓我們的性能很低下,那為什么redis還要使用這種數據結構呢?

    雖然有連鎖更新,但是如上邊案例的事件發生率很小,要連續多個介于250-253大小的節點的概率很小,就算有的話,不是特別多也能很快的解決,不會影響效率。

    總結

    以上是生活随笔為你收集整理的Redis的设计与实现之整数集合和压缩列表的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。