日本免费精品_最新日韩一区_亚洲视频一区在线_a在线视频观看_天天射夜夜骑_粉嫩av一区二区三区_欧美中日韩免费视频_综合图区欧美_国内精品美女在线观看_午夜精品久久久久久久男人的天堂

首頁 > 數據庫 > Redis > 正文

redis內部數據結構之SDS簡單動態字符串詳解

2020-10-28 21:35:05
字體:
來源:轉載
供稿:網友

前言

reids 沒有直接使用C語言傳統的字符串表示(以空字符結尾的字符數組)而是構建了一種名為簡單動態字符串的抽象類型,并為redis的默認字符串表示,因為C字符串不能滿足redis對字符串的安全性、效率以及功能方面的需求

1、SDS 定義

在C語言中,字符串是以'/0'字符結尾(NULL結束符)的字符數組來存儲的,通常表達為字符指針的形式(char *)。它不允許字節0出現在字符串中間,因此,它不能用來存儲任意的二進制數據。

sds的類型定義

typedef char *sds;

 

每個sds.h/sdshdr結構表示一個SDS的值 struct sdshdr{ //記錄buf數組中已使用的字節的數量 //等于sds所保存字符串的長度 int len; //記錄buf中未使用的數據 int free; //字符數組,用于保存字符串 } * free 屬性的值為0,表示這個SDS沒有分配任何未使用的空間 * len 屬性長度為5,表示這個SDS保存一個五字節長的字符串 * buf 屬性是一個char類型的數組,數組的前5個字節分別保存了'R','e','d','i','s'五個字符,而最后一個字節則保存了空字符串'/0' 

肯定有人感到困惑了,竟然sds就等同于char *?

sds和傳統的C語言字符串保持類型兼容,因此它們的類型定義是一樣的,都是char *,在有些情況下,需要傳入一個C語言字符串的地方,也確實可以傳入一個sds。

但是sds和char *并不等同,sds是Binary Safe的,它可以存儲任意二進制數據,不能像C語言字符串那樣以字符'/0'來標識字符串的結束,因此它必然有個長度字段,這個字段在header中

sds的header結構

/* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ char buf[];};struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; /* used */ uint16_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[];};

SDS一共有5種類型的header。目的是節省內存。

一個SDS字符串的完整結構,由在內存地址上前后相鄰的兩部分組成:

  • 一個header。通常包含字符串的長度(len)、最大容量(alloc)和flags。sdshdr5有所不同。
  • 一個字符數組。這個字符數組的長度等于最大容量+1。真正有效的字符串數據,其長度通常小于最大容量。在真正的字符串數據之后,是空余未用的字節(一般以字節0填充),允許在不重新分配內存的前提下讓字符串數據向后做有限的擴展。在真正的字符串數據之后,還有一個NULL結束符,即ASCII碼為0的'/0'字符。這是為了和傳統C字符串兼容。之所以字符數組的長度比最大容量多1個字節,就是為了在字符串長度達到最大容量時仍然有1個字節存放NULL結束符。

除了sdshdr5之外,其它4個header的結構都包含3個字段:

  • len: 表示字符串的真正長度(不包含NULL結束符在內)。
  • alloc: 表示字符串的最大容量(不包含最后多余的那個字節)。
  • flags: 總是占用一個字節。其中的最低3個bit用來表示header的類型。

在各個header的類型定義中,還有幾個需要我們注意的地方:

  • 在各個header的定義中使用了__attribute__ ((packed)),是為了讓編譯器以緊湊模式來分配內存。如果沒有這個屬性,編譯器可能會為struct的字段做優化對齊,在其中填充空字節。那樣的話,就不能保證header和sds的數據部分緊緊前后相鄰,也不能按照固定向低地址方向偏移1個字節的方式來獲取flags字段了。
  • 在各個header的定義中最后有一個char buf[]。我們注意到這是一個沒有指明長度的字符數組,這是C語言中定義字符數組的一種特殊寫法,稱為柔性數組(flexible array member),只能定義在一個結構體的最后一個字段上。它在這里只是起到一個標記的作用,表示在flags字段后面就是一個字符數組,或者說,它指明了緊跟在flags字段后面的這個字符數組在結構體中的偏移位置。而程序在為header分配的內存的時候,它并不占用內存空間。如果計算sizeof(struct sdshdr16)的值,那么結果是5個字節,其中沒有buf字段。
  • sdshdr5與其它幾個header結構不同,它不包含alloc字段,而長度使用flags的高5位來存儲。因此,它不能為字符串分配空余空間。如果字符串需要動態增長,那么它就必然要重新分配內存才行。所以說,這種類型的sds字符串更適合存儲靜態的短字符串(長度小于32)。

至此,我們非常清楚地看到了:sds字符串的header,其實隱藏在真正的字符串數據的前面(低地址方向)。這樣的一個定義,有如下幾個好處:

  • header和數據相鄰,而不用分成兩塊內存空間來單獨分配。這有利于減少內存碎片,提高存儲效率(memory efficiency)。
  • 雖然header有多個類型,但sds可以用統一的char *來表達。且它與傳統的C語言字符串保持類型兼容。如果一個sds里面存儲的是可打印字符串,那么我們可以直接把它傳給C函數,比如使用strcmp比較字符串大小,或者使用printf進行打印。

弄清了sds的數據結構,它的具體操作函數就比較好理解了。

sds的一些基礎函數

  • sdslen(const sds s): 獲取sds字符串長度。
  • sdssetlen(sds s, size_t newlen): 設置sds字符串長度。
  • sdsinclen(sds s, size_t inc): 增加sds字符串長度。
  • sdsalloc(const sds s): 獲取sds字符串容量。
  • sdssetalloc(sds s, size_t newlen): 設置sds字符串容量。
  • sdsavail(const sds s): 獲取sds字符串空余空間(即alloc - len)。
  • sdsHdrSize(char type): 根據header類型得到header大小。
  • sdsReqType(size_t string_size): 根據字符串數據長度計算所需要的header類型。

二、SDS 數組動態分配策略

header信息中的定義這么多字段,其中一個很重要的作用就是實現對字符串的靈活操作并且盡量減少內存重新分配和回收操作。

redis的內存分配策略如下

  • 當SDS的len屬性長度小于1MB時,redis會分配和len相同長度的free空間。至于為什么這樣分配呢,上次用了len長度的空間,那么下次程序可能也會用len長度的空間,所以redis就為你預分配這么多的空間。
  • 但是當SDS的len屬性長度大于1MB時,程序將多分配1M的未使用空間。這個時候我在根據這種慣性預測來分配的話就有點得不償失了。所以redis是將1MB設為一個風險值,沒過風險值你用多少我就給你多少,過了的話那這個風險值就是我能給你臨界值

reids的內存回收策略如下

  • redis的內存回收采用惰性回收,即你把字符串變短了,那么多余的內存空間我先不還給操作系統,先留著,萬一馬上又要被使用呢。短暫的持有資源,既可以充分利用資源,也可以不浪費資源。這是一種很優秀的思想。

綜上所述,redis實現的高性能字符串的結果就把N次字符串操作必會發生N次內存重新分配變為人品最差時最多發生N次重新分配。

/* Enlarge the free space at the end of the sds string so that the caller * is sure that after calling this function can overwrite up to addlen * bytes after the end of the string, plus one more byte for nul term. * * Note: this does not change the *length* of the sds string as returned * by sdslen(), but only the free buffer space we have. */sds sdsMakeRoomFor(sds s, size_t addlen) { void *sh, *newsh; size_t avail = sdsavail(s); size_t len, newlen; char type, oldtype = s[-1] & SDS_TYPE_MASK; int hdrlen;  /* Return ASAP if there is enough space left. */ if (avail >= addlen) return s;  len = sdslen(s); sh = (char*)s-sdsHdrSize(oldtype); newlen = (len+addlen); if (newlen < SDS_MAX_PREALLOC) newlen *= 2; else newlen += SDS_MAX_PREALLOC;  type = sdsReqType(newlen);  /* Don't use type 5: the user is appending to the string and type 5 is * not able to remember empty space, so sdsMakeRoomFor() must be called * at every appending operation. */ if (type == SDS_TYPE_5) type = SDS_TYPE_8;  hdrlen = sdsHdrSize(type); if (oldtype==type) { newsh = s_realloc(sh, hdrlen+newlen+1); if (newsh == NULL) return NULL; s = (char*)newsh+hdrlen; } else { /* Since the header size changes, need to move the string forward,  * and can't use realloc */ newsh = s_malloc(hdrlen+newlen+1); if (newsh == NULL) return NULL; memcpy((char*)newsh+hdrlen, s, len+1); s_free(sh); s = (char*)newsh+hdrlen; s[-1] = type; sdssetlen(s, len); } sdssetalloc(s, newlen); return s;} /* Reallocate the sds string so that it has no free space at the end. The * contained string remains not altered, but next concatenation operations * will require a reallocation. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */sds sdsRemoveFreeSpace(sds s) { void *sh, *newsh; char type, oldtype = s[-1] & SDS_TYPE_MASK; int hdrlen; size_t len = sdslen(s); sh = (char*)s-sdsHdrSize(oldtype);  type = sdsReqType(len); hdrlen = sdsHdrSize(type); if (oldtype==type) { newsh = s_realloc(sh, hdrlen+len+1); if (newsh == NULL) return NULL; s = (char*)newsh+hdrlen; } else { newsh = s_malloc(hdrlen+len+1); if (newsh == NULL) return NULL; memcpy((char*)newsh+hdrlen, s, len+1); s_free(sh); s = (char*)newsh+hdrlen; s[-1] = type; sdssetlen(s, len); } sdssetalloc(s, len); return s;}

三、SDS的特點

sds正是在Redis中被廣泛使用的字符串結構,它的全稱是Simple Dynamic String。與其它語言環境中出現的字符串相比,它具有如下顯著的特點:

  • 可動態擴展內存。SDS表示的字符串其內容可以修改,也可以追加。在很多語言中字符串會分為mutable和immutable兩種,SDS屬于mutable類型的。
  • 二進制安全(Binary Safe)。sds能存儲任意二進制數據。
  • 與傳統的C語言字符串類型兼容。
  • 預分配空間,可以懶惰釋放,在內存緊張的時候也可以縮減不需要的內存
  • 常數復雜度獲取字符串長度
  • 杜絕緩沖區溢出,邊界檢查

四、淺談SDS與string的關系

127.0.0.1:6379> set test testOK127.0.0.1:6379> append test " test"(integer) 9127.0.0.1:6379> get test"test test"127.0.0.1:6379> setbit test 36 1(integer) 0127.0.0.1:6379> get test"test(test"127.0.0.1:6379> getrange test -5 -1"(test"
  • append操作使用SDS的sdscatlen來實現。
  • setbit和getrange都是先根據key取到整個sds字符串,然后再從字符串選取或修改指定的部分。由于SDS就是一個字符數組,所以對它的某一部分進行操作似乎都比較簡單。

但是,string除了支持這些操作之外,當它存儲的值是個數字的時候,它還支持incr、decr等操作。它的內部存儲不是SDS,這種情況下,setbit和getrange的實現也會有所不同。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

參考文章

  • http://blog.csdn.net/xiejingfa/article/details/50972592
  • http://blog.csdn.net/acceptedxukai/article/details/17482611
  • https://segmentfault.com/a/1190000003984537
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲视频在线观看日本a| 国产午夜精品全部视频播放| 日韩视频 中文字幕| 亚洲免费观看视频| 日韩免费电影网站| 日韩欧美一二三| 亚洲女人天堂a在线播放| 视频一区中文字幕国产| 中文字幕高清在线播放| 中文字幕 欧美日韩| 精品在线一区二区| 欧美日韩尤物久久| 欧美日韩精品是欧美日韩精品| 欧美三级在线播放| 国产丝袜在线播放| 一区二区三区在线播放欧美| 欧美va亚洲va日韩∨a综合色| 午夜一区二区三区| 欧美日韩一二三| 国产午夜在线观看| 日韩视频精品在线观看| 国产永久在线观看| 欧美日韩三级视频| 日韩在线视频观看正片免费网站| 亚洲免费精品视频| 在线欧美日韩精品| 视频一区二区国产| 欧美日韩中文字幕| 午夜一区二区三区| 91精品国产欧美日韩| 91精品在线看V| 欧美高清一级片在线| 国产黄色片大全| 日韩视频一区| 久久精品视频免费看| 日韩欧美中文字幕精品| 成人h视频在线观看| 蜜臀久久精品| 国产成人精品av久久| 欧美精品一区二区三区在线播放| 中文字幕亚洲第一| 久久精品卡一| 国产资源在线观看入口av| 国产在线不卡一区| 国产偷久久久精品专区| 黄色一区二区在线| 日韩精品丝袜在线| 天天综合天天综合| 久久精品视频免费看| 日韩亚洲欧美中文三级| 欧美一级日韩一级| 午夜成人鲁丝片午夜精品| 久久久综合精品| 亚洲深夜福利| 日韩亚洲欧美中文字幕| 一区二区三区在线|网站| 日本免费在线视频不卡一不卡二| 日韩av二区| 国产欧美日韩三级| 亚洲免费福利视频| 日韩www在线| 久久精品人妻一区二区三区| 久久久精品网| 欧美 日韩 国产 在线观看| 在线观看精品国产| 欧美日韩高清在线一区| 欧美日韩在线三级| 91精品国产91久久久久久青草 | 日韩欧美高清在线| 黄色在线资源| 国产一卡2卡3卡4卡网站免费| 亚洲三级欧美| 欧美日韩性视频一区二区三区| 欧美日韩在线视频一区| 国产欧美日韩精品综合| 国产黄色在线播放| 顶级网黄在线播放| 精品亚洲永久免费| 亚洲最大黄色| 亚洲欧美中文字幕在线观看| 久久久精品免费免费| 深夜福利亚洲| 亚洲免费观看视频| 欧美不卡一区二区| 欧美日韩高清一区二区不卡| 国产成人精品三级| 一区二区三区中文字幕在线观看| 久久精品一二三| 亚洲综合在线不卡| 在线观看免费国产成人软件| 欧美在线视频一区二区| 精品国产999| 日本不卡免费高清视频| 欧美日韩激情一区| 欧美日韩国产第一页| 国产视频aaa| 日韩精品福利一区二区三区| 欧美三级视频在线| 欧美日韩在线不卡| 伊人中文字幕在线观看| 69av亚洲| 91久久精品国产| 欧美综合精品| 国产一级在线免费观看| 精品九九久久| 国产在线第一页| 91精品国产高清| 久久精品久久精品亚洲人| 国产中文在线| 日韩黄色在线播放| 在线观看av的网站| 中文字幕2020第一页| 国产欧美久久久| 99视频在线看| 91精品国产免费| 国产小视频在线| 中文字幕第一页在线播放| 国产123在线| 日韩精品手机在线| 中文字幕无线码一区| 中文字幕在线日韩| 亚洲中文字幕一区| 久久在线91| av午夜在线| 在线日韩精品视频| 国产wwww| 国产一区 二区 三区一级| 欧美日韩精品是欧美日韩精品| 亚洲一卡二卡在线观看| 日韩欧美字幕| 亚洲 国产 欧美 日韩| av免费看在线| 国产福利不卡| 日韩精品视频免费看| 久久久久久99精品| 精品国自产在线观看| 欧美日韩国产观看视频| 日韩精品―中文字幕| 国产午夜精品一区二区三区视频| 日韩三级视频中文字幕| 国产婷婷色一区二区三区| 国产一区久久| 一区二区三区在线播放欧美| 国产91久久久久| 国产三级做爰在线观看| 亚洲三级中文字幕| 欧美三级日韩在线| 国产小视频在线观看| av中文在线播放| 欧美日韩激情在线一区二区三区 | 精品在线一区二区| 欧美1区免费| 久久精品网站免费观看| 日韩精品―中文字幕| 亚洲一区视频在线观看视频| 国产在线拍偷自揄拍精品| 日韩中文字幕久久| 91精品国产自产| 精品国产免费视频| 久久精品人妻一区二区三区| 91精品国产综合久久福利| 国产 欧美 日韩 在线| 久久香蕉一区| 久久精品国产成人一区二区三区| 欧美一级免费看| 色综合久久88色综合天天免费| 精品久久久网| 欧美国产综合视频| 日韩色在线观看| 欧美日韩在线国产| 日韩免费精品视频| 日韩视频在线免费播放| 亚洲免费精品| 国产导航在线| 国产主播中文字幕| 国产一级网站视频在线| 国产三级视频在线播放线观看| 91精品国产色综合久久不卡蜜臀| 国产网站欧美日韩免费精品在线观看| 日韩视频在线一区二区| 免费视频二区| 日韩a一区二区| 国产日产一区二区三区| aa国产成人| 国产福利精品导航| 亚洲欧洲在线观看av| 国产欧美日韩在线看| 国产999精品在线观看| 中文字幕在线国产| 日韩欧美看国产| 中文字幕人成乱码在线观看| 日韩欧美中文在线| 亚洲日本精品视频| 亚洲欧美久久234| 999视频精品| 先锋男人资源站| 国产123在线| 91精品婷婷国产综合久久竹菊| 日韩 国产 一区| 欧美日韩国产中字| 亚洲国产欧美日韩精品| 欧美国产一级片| 日韩欧美一级在线| 日韩欧美在线1卡| 国产天堂素人系列在线视频| 欧美成人一区二区| 久久精品网站免费观看| 欧美日韩久久久| 中文字幕在线观看欧美| 国产一区激情在线| av中文资源在线| 亚洲中文字幕在线一区| 欧美日韩一级视频| 91久久久精品| 亚洲一区精品在线| 综合图区亚洲白拍在线| 91精品国产丝袜白色高跟鞋| 亚洲欧美中文在线视频| 一区二区三区在线播放欧美| 91精品免费观看| 欧美亚洲另类制服自拍| av一级在线| 精品国产91乱高清在线观看| 高清国产一区| 九一精品国产| 中文字幕 欧美日韩| 国产乱一区二区| 欧美日韩成人一区二区| 国产资源在线观看| 91精品久久久久久蜜臀| 免费一级欧美在线观看视频| 日韩欧美在线综合网| 久久精品女人| 天天综合日日夜夜精品| 欧美日韩激情一区| 日韩在线一区二区| 国产成人精品三级| 日韩欧美国产视频| 欧美熟妇乱码在线一区| 欧美国产亚洲一区| a视频免费在线观看| 久久精品www| 日韩欧美在线视频| 国产免费不卡av| 久久av免费| 国产一级片播放| 亚洲福利精品在线| 国内精品露脸在线视频播放| 日韩欧美在线精品| 粉嫩喷白浆久久| 在线免费播放av| 日韩精品视频在线观看免费| 精品国产乱码一区二区| av免费网站在线| 欧美日韩在线观看成人| 一区二区在线观看不卡| 国产中文在线播放| 亚洲狠狠婷婷综合久久久久图片| 亚洲福利在线视频| 欧美片网站免费| 亚洲男人在线| 日韩在线一区二区| 视频一区二区国产| 成人久久在线| 亚洲一级网站| а√天堂8资源中文在线| 午夜黄色小视频| 一级片在线播放| 精品久久久网| 中文字幕 日韩 欧美| 粉嫩喷白浆久久| 日韩欧美一级在线播放| 欧美日韩久久久| 日韩影院二区| 中文字幕精品一区二| 日韩视频一区二区在线观看| www.xxxx精品| 中文字幕亚洲免费| 91精品国产综合久久久久久漫画| 久久香蕉av| 欧美日韩在线网站| 精品在线一区二区| 蜜桃久久久久| 国产福利在线播放| 日韩中文字幕综合| 欧美一级免费在线观看| 国产欧美日韩三级| 欧美成人一区二区| 亚洲国产无线乱码在线观看| 黄色一区二区在线| 在线国产99| 欧美日韩国产第一页| 欧美在线亚洲一区| 91精品国产高清久久久久久| 国产拍揄自揄精品视频麻豆| 国产资源在线观看入口av| 国产日韩精品在线看| 久久久91精品| 中文字幕国产在线| 九九在线精品| 91精品视频在线| 国产小视频在线观看| 国产亚洲福利| 欧美日韩国产大片| 亚洲国产无线乱码在线观看 | 欧美黄页在线免费观看| 国产三级视频在线| 国产999精品在线观看| 91精品国产综合久久久蜜臀粉嫩 | 日韩激情一区| 亚洲一区中文字幕在线观看| 久久久久黄色| 日韩精品欧美在线| 日韩三级高清在线| 日韩精品在线免费看| 久久精品一级爱片| 午夜成人鲁丝片午夜精品| 精品日韩视频在线观看| 亚洲福利精品在线| 国产裸体歌舞团一区二区| 国产99在线|亚洲| 亚洲国产综合久久| 日韩在线视频在线观看| 樱花草www在线| 激情婷婷亚洲| 欧美日韩在线国产| 91精品国产网站| 欧美日韩亚洲不卡| 粉嫩粉嫩芽的虎白女18在线视频| 中文字幕亚洲二区| 色综合久久88色综合天天免费| 亚洲一区激情| 日韩精品一区二区三区视频播放| 亚洲狠狠婷婷综合久久久久图片| 亚洲免费福利视频| 精品1区2区3区| 久久久91精品| 亚洲午夜av| 欧美日韩国产在线看| 国产欧美高清在线| 亚洲免费精品| 精品在线观看一区| 日韩欧美国产一二三区| 日韩在线视频免费观看高清中文| 日韩欧美亚洲日产国| 国产在线导航| 亚洲成a人片在线www| 精品日韩av一区二区| 视频一区二区精品的福利| 亚洲羞羞网站| 日韩一级在线视频 | 久久久91精品国产| 91精品在线看V| 精品久久久视频| 欧美日韩国产在线观看| 久久精品人妻一区二区三区| 国产乱国产乱老熟300| 91精品在线观| 国产视频二区| 天堂在线中文| 在线中文字幕视频| 国产在线观看91| 91亚洲国产高清| 影音先锋一区二区资源站| 国产在线观看91| 国产免费一级| 91精品视频在线| 久久蜜桃精品| 日韩欧美国产免费| 日韩高清不卡一区| 国产欧美日韩成人| 日韩欧美综合在线视频| 国产在线精品日韩| 九一久久久久久| 国产色在线 com| 亚洲综合在线小说| 精品人妻一区二区三区视频| 日韩免费看网站| 亚洲视频在线观看三级| 一区二区三区在线播放欧美| 99精品视频99| 欧美日韩国产一区| 免费高清视频日韩| 国产黄色精品| 久久69成人| 亚洲一级特黄| 影音先锋一区二区资源站| 日韩精品福利一区二区三区| 日韩视频精品| 国产福利一区在线观看| 日韩亚洲一区中文字幕| 国产成人中文字幕| 亚洲乱码一区av黑人高潮| 久久久99久久精品欧美| 91精品国产丝袜白色高跟鞋| 在线一区二区三区精品| 一区在线视频观看| 日本亚洲视频在线| 亚洲高清在线观看一区| 日韩国产亚洲欧美|