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

歡迎訪問 生活随笔!

生活随笔

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

数据库

跟着大彬读源码 - Redis 6 - 对象和数据类型(下)

發布時間:2023/12/20 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 跟着大彬读源码 - Redis 6 - 对象和数据类型(下) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 1 哈希對象
  • 2 集合對象
  • 3 有序集合對象
  • 總結

繼續擼我們的對象和數據類型。

上節我們一起認識了字符串和列表,接下來還有哈希、集合和有序集合。

1 哈希對象

哈希對象的可選編碼分別是:ziplist 和 hashtable。

1.1 ziplist 編碼的哈希對象

ziplist 編碼的哈希對象使用壓縮列表作為底層實現。每當有新的鍵值對要加入到哈希對象時,程序會先將保存了的壓縮列表節點推入到表尾,然后再將保存了的壓縮列表節點推入到表尾。因此:

  • 保存了鍵值對的兩個節點總是緊挨在一起,保存鍵的節點在前,保存值的節點在后;
  • 先添加到哈希對象中的鍵值對會被仿造壓縮列表的表頭方向,后添加的鍵值對會被放在壓縮列表的表尾方向。

執行以下 HSET 命令,服務器將創建一個如圖 9 所示的列表對象作為 profile 鍵的值:

127.0.0.1:6379> HSET profile name "Tom" (integer) 1 127.0.0.1:6379> HSET profile age "25" (integer) 1 127.0.0.1:6379> HSET profile career "Programer" (integer) 1 127.0.0.1:6379> OBJECT ENCODING profile "ziplist"

其中對象所使用的壓縮列表如圖 10 所示:

1.2 hashtable 編碼的

hashtable 編碼的哈希對象使用字典作為底層實現。哈希對象中的每個鍵值對都使用一個字典鍵值對來保存:

  • 字典中的每個鍵都是一個字符串對象,對象中保存了鍵值對的鍵;
  • 字典中的每個值都是一個字符串對象,對象中保存了鍵值對的值。

如果前面的 profile 鍵使用的是 hashtable 編碼的哈希對象,那么這個哈希對象應該如圖 11 所示:

1.3 編碼轉換

當哈希對象同時符合下面兩個條件時,將使用 ziplist 編碼:

  • 哈希對象保存的所有鍵值對中,鍵和值的字符串長度都小于 64 個字節;
  • 哈希對象保存的鍵值對數量小于 512 個。
  • 上述條件中的臨界值對應 redis.conf 文件中的配置:hash-max-ziplist-value 和 hash-max-ziplist-entries。

    在 3.2 版本中,新增一個哈希鍵值對時,實際上總是先創建一個 ziplist 編碼的哈希對象,然后再進行轉換檢查。
    關于何時進行編碼轉換,有兩種情況發生:

  • 更新或新增鍵值對時,如果值的字節數大于 hash-max-ziplist-value,將從 ziplist 編碼轉成 hashtable 編碼;
  • 新增鍵值對時,如果哈希中的鍵值對數量大于 hash-max-ziplist-entries,將從 ziplist 編碼轉成 hashtable 編碼。
  • 要注意的是,上述發生轉換的情況,都不會出現從 hashtable 轉成 ziplist 的情況,即使符合條件。

    關于哈希編碼轉換的函數,可以參考 t_hash.c/hashTypeConvert,源碼如下:

    # o 是原始對象,enc 是目標編碼。 void hashTypeConvert(robj *o, int enc) {if (o->encoding == OBJ_ENCODING_ZIPLIST) { // 原始編碼是 OBJ_ENCODING_ZIPLIST 才進行轉換hashTypeConvertZiplist(o, enc);} else if (o->encoding == OBJ_ENCODING_HT) {serverPanic("Not implemented");} else {serverPanic("Unknown hash encoding");} }

    2 集合對象

    集合對象的可選編碼有:intset 和 hashtable。

    2.1 intset 編碼的集合對象

    intset 編碼的集合對象使用整數集合作為底層實現,集合對象包含的所有元素都被保存在整數集合里面。

    執行以下 SADD 命令,將創建一個如圖 12 所示的 intset 編碼的集合對象:

    127.0.0.1:6379> SADD numbers 1 3 5 (integer) 3 127.0.0.1:6379> OBJECT ENCODING numbers "intset"

    2.2 hashtable 編碼的集合對象

    hashtable 編碼的集合對象使用字典作為底層實現,字典的每個鍵都是一個字符串對象,每個字符串對象中又包含了一個集合元素,而字典的值則全部設置為 NULL。

    執行以下 SADD 命令,將創建一個如圖 13 所示的 hashtable 編碼的集合對象:

    127.0.0.1:6379> SADD fruits "apple" "banana" "cherry" (integer) 3 127.0.0.1:6379> OBJECT ENCODING fruits "hashtable"

    2.3 編碼轉換

    當集合對象同時滿足以下兩個條件時,對象使用 intset 編碼:

  • 集合對象保存的所有元素都是可以被 long double 表示整數值;
  • 集合對象保存的元素數量不超過 512 個。
  • 上述條件中的臨界值對應 redis.conf 文件中的配置:set-max-intset-entries。

    對于集合對象,在新增第一個鍵值對時,就會對鍵值對中的值進行檢查,如果是符合條件的整數值,就會創建一個 intset 編碼的集合對象,否則,則創建 hashtable 編碼的集合對象。

    關于何時進行編碼轉換,有兩種情況發生:

  • 更新或新增鍵值對時,如果不能用 long double 表示,將從 intset 編碼轉成 hashtable 編碼;
  • 新增鍵值對時,如果集合中的鍵值對數量大于 set-max-intset-entries,將從 intset 編碼轉成 hashtable 編碼。
  • 同樣,上述發生轉換的情況,都不會出現從 hashtable 轉成 intset 的情況,即使符合條件。

    關于哈希編碼轉換的函數,可以參考 t_set.c/setTypeConvert,源碼如下:

    # setobj 是原始對象,enc 是目標編碼。 hvoid setTypeConvert(robj *setobj, int enc) {setTypeIterator *si;serverAssertWithInfo(NULL,setobj,setobj->type == OBJ_SET && setobj->encoding == OBJ_ENCODING_INTSET);if (enc == OBJ_ENCODING_HT) { // 只能轉成 OBJ_ENCODING_HT 編碼int64_t intele;dict *d = dictCreate(&setDictType,NULL);robj *element;/* Presize the dict to avoid rehashing */dictExpand(d,intsetLen(setobj->ptr));/* To add the elements we extract integers and create redis objects */si = setTypeInitIterator(setobj);while (setTypeNext(si,&element,&intele) != -1) {element = createStringObjectFromLongLong(intele);serverAssertWithInfo(NULL,element,dictAdd(d,element,NULL) == DICT_OK);}setTypeReleaseIterator(si);setobj->encoding = OBJ_ENCODING_HT;zfree(setobj->ptr);setobj->ptr = d;} else {serverPanic("Unsupported set conversion");} }

    3 有序集合對象

    有序集合對象的可選編碼有:ziplist 和 skiplist。

    3.1 ziplist 編碼的有序集合對象

    intset 編碼的集合對象使用壓縮列表作為底層實現。每個集合元素使用兩個緊挨在一起的壓縮列表節點來保存。第一個節點保存元素的成員(member),第二個成員保存元素的分值(score)。

    壓縮列表內的集合元素按分值從小到大排序,分值較小的元素被放置在表頭的方向,而分值較大的元素則被放置在靠近表尾的方向。

    執行以下 SADD 命令,將創建一個如圖 14 所示的 ziplist 編碼的集合對象:

    127.0.0.1:6379> ZADD price 8.5 apple 5.0 banana 6.0 cherry (integer) 3 127.0.0.1:6379> OBJECT ENCODING price "ziplist"

    底層結構 ziplist 如圖 15 所示:

    3.2 skiplist 編碼的集合對象

    skiplist 編碼的集合對象使用 zset 作為底層實現。一個 zset 結構同時包含一個字典和一個跳躍表。結構源碼如下:

    # server.h typedef struct zset {dict *dict;zskiplist *zsl; } zset;

    zset 結構中的 zsl 跳躍表按分值從小到大保存了所有集合元素,每個跳躍表節點都保存了一個集合元素。

    跳躍表節點的 object 屬性保存了元素的成員,而跳躍表節點的 score 屬性則保存了元素的分支。**程序通過這個跳躍表,對有序集合進行范圍型操作。比如 ZRANK、ZRANGE 等命令就是基于跳躍表 API 來實現的。

    除此之外,zset 結構中的 dict 字典為有序集合創建了一個從成員到分值的映射。字典中的每個鍵值對都保存了一個集合元素:字典中的鍵保存了元素的成員,而字典的值則保存了元素的分值。通過這個字典,程序用 O(1) 復雜度查找給定成員的分值。

    有序集合每個元素的成員都是一個字符串對象,而每個元素的分值都是一個 double 類型的浮點數。值得一提的是,雖然 zset 結構同時使用跳躍表和字典保存了有序集合的元素,但這兩種數據結構都會通過指針來共享相同元素的成員和分值,所以不會產生任何重復成員和分值,也不會因此而浪費額外的內存。

    如果前面 price 鍵創建的不是 ziplist 編碼的有序集合對象,而是 skiplist 編碼,那么這個有序集合對象將會如圖 16 所示,而對象所使用的 zset 結果將會如圖 17 所示:

    圖 17 中,為了展示方便,重復展示了各個元素的成員和分值。實際上,它們是共享元素的成員和分值。

    3.3 編碼轉換

    當有序集合對象同時滿足以下兩個條件時,對象使用 ziplist 編碼:

  • 有序集合對象保存的元素數量不超過 128 個。
  • 有序集合中保存的所有元素成員的長度都小于 64 個字節。
  • 上述條件中的臨界值對應 redis.conf 文件中的配置:zset-max-ziplist-entries 和 zset-max-ziplist-value。

    對于集合對象,在新增鍵值對時,就會對集合元素以及鍵值對中的值進行檢查,如果是符合條件,就會創建一個 ziplist 編碼的集合對象,否則,則創建 skiplist 編碼的集合對象。對應源碼如下:

    # t_zset.c/zaddGenericCommand ... zobj = lookupKeyWrite(c->db,key); if (zobj == NULL) {if (xx) goto reply_to_client; /* No key + XX option: nothing to do. */if (server.zset_max_ziplist_entries == 0 ||server.zset_max_ziplist_value < sdslen(c->argv[scoreidx+1]->ptr)){# 對象元素數量為 0,或者zobj = createZsetObject();} else {zobj = createZsetZiplistObject();}dbAdd(c->db,key,zobj); } else {if (zobj->type != OBJ_ZSET) {addReply(c,shared.wrongtypeerr);goto cleanup;} }

    總結

  • 哈希對象有 ziplisthashtable 編碼。
  • 集合對象有 intsethashtable 編碼。
  • 有序集合對象有 ziplistskiplist 編碼。
  • 轉載于:https://www.cnblogs.com/BeiGuo-FengGuang/p/11235878.html

    總結

    以上是生活随笔為你收集整理的跟着大彬读源码 - Redis 6 - 对象和数据类型(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

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