redis 當中, sds字符串, adlist雙向鏈表, dict字典, ziplist壓縮鏈表, intset整數集合等均爲底層數據結構redis
redis 並無使用這些基本數據結構來實現數據庫應用, 而是基於這些底層數據結構之上, 構建了一個對象系統, 全部的操做都是基於對象來進行操做算法
對象結構數據庫
// redis 對象結構 typedef struct redisObject { // 類型 unsigned type:4; // 編碼 unsigned encoding:4; // 對象最後一次被訪問的時間 unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */ // 引用計數 int refcount; // 指向實際值的指針 void *ptr; } robj;
對象類型api
// 對象類型 // 字符串 #define REDIS_STRING 0 // 鏈表 #define REDIS_LIST 1 // 集合 #define REDIS_SET 2 // 有序集合 #define REDIS_ZSET 3 // 哈希 #define REDIS_HASH 4
對象編碼安全
// 對象編碼 // 普通的 sds 結構 #define REDIS_ENCODING_RAW 0 /* Raw representation */ // 整型 #define REDIS_ENCODING_INT 1 /* Encoded as integer */ // 哈希 #define REDIS_ENCODING_HT 2 /* Encoded as hash table */ // 壓縮圖, 沒看到有應用 #define REDIS_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ // 普通鏈表 #define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */ // 壓縮鏈表 #define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ // 整數集合 #define REDIS_ENCODING_INTSET 6 /* Encoded as intset */ // 跳躍表 #define REDIS_ENCODING_SKIPLIST 7 /* Encoded as skiplist */ // emb 編碼的字符串 #define REDIS_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
引用計數服務器
總結數據結構
redis 的對象系統總共有 5 種類型, 可是在使用上每種類型根據不一樣的使用場景會採用不一樣的編碼, 不一樣的對象編碼會使用不一樣的底層存儲結構, 這樣作是爲了性能考慮, 因爲數據量的不一樣, 使用不一樣的結構對效率的影響不一樣dom
對象類型函數
名稱 類型 REDIS_STRING 字符串 REDIS_LIST 列表 REDIS_SET 集合 REDIS_ZSET 有序集合 REDIS_HASH 哈希 對象編碼性能
名稱 編碼 REDIS_ENCODING_RAW 普通 sds 字符串 REDIS_ENCODING_INT 整數 REDIS_ENCODING_EMBSTR emb 編碼的字符串 REDIS_ENCODING_LINKEDLIST 普通鏈表 REDIS_ENCODING_ZIPLIST 壓縮鏈表 REDIS_ENCODING_HT 哈希 REDIS_ENCODING_SKIPLIST 跳躍表 REDIS_ENCODING_INTSET 整數集合 REDIS_ENCODING_ZIPMAP 壓縮圖 對象類型與編碼之間的關係
類型 編碼 對象 REDIS_STRING REDIS_ENCODING_RAW 普通 sds 字符串 REDIS_STRING REDIS_ENCODING_INT 整數字符串 REDIS_STRING REDIS_ENCODING_EMBSTR emb 編碼字符串 REDIS_LIST REDIS_ENCODING_LINKEDLIST 普通雙向鏈表 REDIS_LIST REDIS_ENCODING_ZIPLIST 壓縮鏈表實現的鏈表結構 REDIS_SET REDIS_ENCODING_HT 哈希結構實現的集合 REDIS_SET REDIS_ENCODING_INTSET 整數集合實現的結合 REDIS_ZSET REDIS_ENCODING_SKIPLIST 跳躍表實現的有序集合 REDIS_ZSET REDIS_ENCODING_ZIPLIST 壓縮鏈表實現的有序集合 REDIS_HASH REDIS_ENCODING_HT 哈希表實現的哈希 REDIS_HASH REDIS_ENCODING_ZIPLIST 壓縮鏈表實現的哈希
字符串對象
long long 整型在 redis 中是使用字符串存儲的
// 根據傳入的 long long 整數, 建立字符串對象 robj *createStringObjectFromLongLong(long long value) { robj *o; /* * value 大小符合 REDIS_SHARED_INTEGERS 共享整數範圍 * 返回一個共享對象 */ if (value >= 0 && value < REDIS_SHARED_INTEGERS) { incrRefCount(shared.integers[value]); o = shared.integers[value]; } else { // 不符合共享範圍,建立一個新的整數對象 if (value >= LONG_MIN && value <= LONG_MAX) { // 設置相應的 robj 的值 o = createObject(REDIS_STRING, NULL); o->encoding = REDIS_ENCODING_INT; o->ptr = (void*)((long)value); // 值不能用 long 類型保存(long long 類型),將值轉換爲字符串, // 並建立一個 REDIS_ENCODING_RAW 的字符串對象來保存值 } else { o = createObject(REDIS_STRING,sdsfromlonglong(value)); } } return o; }
對於整數, redis 有一個共享整數的概念, 用於將一些經常使用範圍的整數在 redis 啓動時就建立成對象, 後續全部落在這個範圍內的整數, 均使用這個共享對象, 節省了大量整數的對象建立過程
共享整數範圍閾值爲 10000
#define REDIS_SHARED_INTEGERS 10000
整數的編碼類型不必定都是 REDIS_ENCODING_INT, 當整數值超過了 long 的範圍時, 存儲的編碼類型會變爲 REDIS_ENCODING_RAW
long double 浮點型在 redis 中也是使用字符串存儲的
// 將 long double 浮點型存儲爲字符串 robj *createStringObjectFromLongDouble(long double value) { char buf[256]; int len; // 使用 17 位小數精度,這種精度能夠在大部分機器上被 rounding 而不改變 len = snprintf(buf,sizeof(buf),"%.17Lf", value); // 移除尾部的 0 if (strchr(buf,'.') != NULL) { char *p = buf+len-1; while(*p == '0') { p--; len--; } // 若是不須要小數點,那麼移除它 if (*p == '.') len--; } // 建立對象 return createStringObject(buf,len); }
字符串須要 2 個結構體, robj 和 sdshdr, robj 用來封裝成 redis object, sdshdr 用來存儲真正的字符串內容
建立 emb 編碼與 raw 編碼的字符串有一個閾值 REDIS_ENCODING_EMBSTR_SIZE_LIMIT, 當超過這個閾值, 當小於等於這個閾值時, 以 emb 編碼; 不然以 raw 編碼, REDIS_ENCODING_EMBSTR_SIZE_LIMIT 值爲 39
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39 // 建立字符串對象 robj *createStringObject(char *ptr, size_t len) { // 當小於等於 REDIS_ENCODING_EMBSTR_SIZE_LIMIT時, 以 emb 編碼 if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else // 不然以 raw 編碼 return createRawStringObject(ptr,len); }
建立 emb 編碼的字符串僅須要 1 次內存分配, raw 編碼的字符串須要 2 次內存分配, 相應的釋放內存時也是如此
emb 編碼的字符串 robj, sdshdr 內存是連續的, 而 raw 編碼的字符串內存是分開的, emb 編碼的字符串性能更好
建立 emb 編碼字符串
// 建立 emb 編碼的字符串 robj *createEmbeddedStringObject(char *ptr, size_t len) { // 分配 robj, sdshdr 內存 robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1); struct sdshdr *sh = (void*)(o+1); // 設置 robj 的值 o->type = REDIS_STRING; o->encoding = REDIS_ENCODING_EMBSTR; o->ptr = sh+1; o->refcount = 1; o->lru = LRU_CLOCK(); // 設置 sdshdr 的值 sh->len = len; sh->free = 0; if (ptr) { memcpy(sh->buf,ptr,len); sh->buf[len] = '\0'; } else { memset(sh->buf,0,len+1); } return o; }
建立 raw 編碼字符串
// 建立 raw 編碼字符串 robj *createRawStringObject(char *ptr, size_t len) { // sdsnewlen 函數分配了 sdshdr 的內存 return createObject(REDIS_STRING,sdsnewlen(ptr,len)); }
robj *createObject(int type, void *ptr) { // 分配 robj 的內存 robj *o = zmalloc(sizeof(*o)); // 設置 robj 的值 o->type = type; o->encoding = REDIS_ENCODING_RAW; o->ptr = ptr; o->refcount = 1; o->lru = LRU_CLOCK(); return o; }
字符串比較根據不一樣的 flag 使用不一樣的比較方法
flags
// 二進制安全的方式, 調用 memcmp 函數 #define REDIS_COMPARE_BINARY (1<<0) // 根據 ascii 碼比較, 調用 strcoll 函數 #define REDIS_COMPARE_COLL (1<<1)
鏈表對象
對象嵌套
redis object 裏有個對象嵌套的概念, 就是底層存儲的數據, 例如字符串, 實際上也是以字符串對象 sdshdr 存在的
redis 鏈表對象的編碼分爲 linkedlist (雙端鏈表), ziplist (壓縮鏈表)
redis 鏈表對象的編碼轉換
當節點的長度大於 64 字節, 轉換爲雙端鏈表
void listTypeTryConversion(robj *subject, robj *value) { // 確保 subject 爲 ZIPLIST 編碼 if (subject->encoding != REDIS_ENCODING_ZIPLIST) return; if (sdsEncodedObject(value) && // 看字符串是否過長 sdslen(value->ptr) > server.list_max_ziplist_value) // 將編碼轉換爲雙端鏈表 listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST); }
當鏈表存儲的節點數量大於等於 512 個, 轉換爲雙端鏈表
void listTypePush(robj *subject, robj *value, int where) { // 是否須要轉換編碼? listTypeTryConversion(subject,value); if (subject->encoding == REDIS_ENCODING_ZIPLIST && ziplistLen(subject->ptr) >= server.list_max_ziplist_entries) listTypeConvert(subject,REDIS_ENCODING_LINKEDLIST); // 省略 ... }
server.list_max_ziplist_value 值在初始化服務器配置時設置爲 REDIS_LIST_MAX_ZIPLIST_VALUE
server.list_max_ziplist_entries 值在初始化服務器配置時設置爲 REDIS_LIST_MAX_ZIPLIST_ENTRIES
// 鏈表結構從 ziplist 編碼轉換爲 linkedlist 編碼的閾值 // 最大節點數量閾值 #define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512 // 最大字符串長度閾值 #define REDIS_LIST_MAX_ZIPLIST_VALUE 64 void initServerConfig() { // 省略 server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES; server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE; // 省略 ... }
集合對象
redis 集合的編碼轉換
集合的 intset 編碼存儲的均爲整數
集合的操做 api 在存入 intset 編碼時, 均會調用 isObjectRepresentableAsLongLong 函數, 來判斷是不是整數集合保存的元素數量不能超過 512 (REDIS_SET_MAX_INTSET_ENTRIES)
int setTypeAdd(robj *subject, robj *value) { // 省略 ... // 添加成功 // 檢查集合在添加新元素以後是否須要轉換爲字典 if (intsetLen(subject->ptr) > server.set_max_intset_entries) setTypeConvert(subject,REDIS_ENCODING_HT); // 省略 ... }
server.set_max_intset_entries, 若集合的元素數量大於此值, 會將 intset 編碼轉換爲 ht 編碼
#define REDIS_SET_MAX_INTSET_ENTRIES 512 void initServerConfig() { // 省略 ... server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES; // 省略 ... }
有序集合對象
有序集合結構
// 有序集合 typedef struct zset { // 字典, 鍵爲成員, 值爲分值 dict *dict; // 跳躍表, 按分值排序成員 zskiplist *zsl; } zset;
有序集合 ziplist 編碼與 skiplist 編碼之間的轉換
當執行集合命令時, 判斷一些規則, 來決定是否使用 skiplist 編碼
有序集合保存的元素數量大於 (128) server.zset_max_ziplist_entries
#define REDIS_ZSET_MAX_ZIPLIST_ENTRIES 128
有序集合保存的元素大小大於 (64) server.zset_max_ziplist_value
#define REDIS_ZSET_MAX_ZIPLIST_VALUE 64
命令距離
void zaddGenericCommand(redisClient *c, int incr) { // 省略 ... if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries) zsetConvert(zobj,REDIS_ENCODING_SKIPLIST); if (sdslen(ele->ptr) > server.zset_max_ziplist_value) zsetConvert(zobj,REDIS_ENCODING_SKIPLIST); // 省略 ... }
哈希對象
hash 的 ziplist 編碼將鍵和值分別存放在 ziplist 的 2 個節點, 鍵在前, 值在後
redis hash 的編碼轉換
當知足如下 2 個條件時, redis hash 對象會使用 ziplist 編碼
當 hash 的鍵值對數量小於 512 (server.hash_max_ziplist_entries)
#define REDIS_HASH_MAX_ZIPLIST_ENTRIES 512 int hashTypeSet(robj *o, robj *field, robj *value) { // 省略 ... // 檢查在添加操做完成以後,是否須要將 ZIPLIST 編碼轉換成 HT 編碼 if (hashTypeLength(o) > server.hash_max_ziplist_entries) hashTypeConvert(o, REDIS_ENCODING_HT); // 省略 ... }
當 hash 的全部鍵和值的字符串長度均小於 64 字節 (server.hash_max_ziplist_value)
#define REDIS_HASH_MAX_ZIPLIST_VALUE 64 void hashTypeTryConversion(robj *o, robj **argv, int start, int end) { int i; // 若是對象不是 ziplist 編碼,那麼直接返回 if (o->encoding != REDIS_ENCODING_ZIPLIST) return; // 檢查全部輸入對象,看它們的字符串值是否超過了指定長度 for (i = start; i <= end; i++) { if (sdsEncodedObject(argv[i]) && sdslen(argv[i]->ptr) > server.hash_max_ziplist_value) { // 將對象的編碼轉換成 REDIS_ENCODING_HT hashTypeConvert(o, REDIS_ENCODING_HT); break; } } }
類型檢查
命令多態
內存回收
對象共享
- 不一樣鍵的值指針指向的是同一個值對象
- 值對象的引用計數 +1
函數 | 做用 | 備註 |
---|---|---|
createObject | 建立 robj 對象 | robj createObject(int type, void ptr) |
createRawStringObject | 建立 raw 編碼的字符串對象 | robj createRawStringObject(char ptr, size_t len) |
createEmbeddedStringObject | 建立 emb 壓縮算法壓縮的字符串對象 | robj createRawStringObject(char ptr, size_t len) |
createStringObject | 建立字符串對象, raw 或 emb 編碼 | robj createStringObject(char ptr, size_t len) |
createStringObjectFromLongLong | 建立 int 編碼的字符串對象 | robj *createStringObjectFromLongLong(long long value) |
createStringObjectFromLongDouble | 建立浮點數的字符串對象, raw 或 emb 編碼 | robj *createStringObjectFromLongDouble(long double value) |
dupStringObject | 複製字符串對象 | robj dupStringObject(robj o) |
createListObject | 建立 linkedlist 編碼的列表對象 | robj *createListObject(void) |
createZiplistObject | 建立 ziplist 編碼的列表對象 | robj *createZiplistObject(void) |
createSetObject | 建立 ht 編碼的集合對象 | robj *createSetObject(void) |
createIntsetObject | 建立 intset 編碼的集合對象 | robj *createIntsetObject(void) |
createHashObject | 建立 ziplist 編碼的哈希對象 | robj *createHashObject(void) |
createZsetObject | 建立 skiplist 編碼的有序集合對象 | robj *createZsetObject(void) |
createZsetZiplistObject | 建立 ziplist 編碼的有序集合對象 | robj *createZsetZiplistObject(void) |
freeStringObject | 釋放 raw 編碼的字符串對象 | void freeStringObject(robj *o) |
freeListObject | 釋放鏈表對象 | void freeListObject(robj *o) |
freeSetObject | 釋放集合對象 | void freeSetObject(robj *o) |
freeZsetObject | 釋放有序集合對象 | void freeZsetObject(robj *o) |
freeHashObject | 釋放哈希對象 | void freeHashObject(robj *o) |
incrRefCount | 爲對象的引用加 1 | void incrRefCount(robj *o) |
decrRefCount | 爲對象的引用減 1 | void decrRefCount(robj *o) |
decrRefCountVoid | 對象的引用減 1 | void decrRefCountVoid(void *o) |
resetRefCount | 重置對象的 refcount 爲 0 | robj resetRefCount(robj obj) |
checkType | 檢查對象 o 的類型是否符合 type, 並返回客戶端信息 | int checkType(redisClient c, robj o, int type) |
isObjectRepresentableAsLongLong | 對象 o 是否能夠表示爲 long long 類型, 將轉換後的值存入到 llval | int isObjectRepresentableAsLongLong(robj o, long long llval) |
tryObjectEncoding | 嘗試對字符串對象進行編碼, 以節約內存 | robj tryObjectEncoding(robj o) |
getDecodedObject | 將傳入的 robj 對象解析爲字符串對象 | robj getDecodedObject(robj o) |
compareStringObjectsWithFlags | 比較字符串大小, 根據傳入的 flag 使用不一樣的函數比較 | int compareStringObjectsWithFlags(robj a, robj b, int flags) |
compareStringObjects | 以二進制安全方式比較字符串大小 | int compareStringObjects(robj a, robj b) |
collateStringObjects | 以 strcoll 函數比較字符串大小 | int collateStringObjects(robj a, robj b) |
equalStringObjects | 判斷兩個字符串是否相等 | int equalStringObjects(robj a, robj b) |
stringObjectLen | 獲取字符串對象中字符串長度 | size_t stringObjectLen(robj *o) |
getDoubleFromObject | 從字符串對象 o 中獲取 double 值, 存入 target | int getDoubleFromObject(robj o, double target) |
getDoubleFromObjectOrReply | 從對象 o 中獲取 double 值, 存入 target; 若失敗返回給定信息 | int getDoubleFromObjectOrReply(redisClient c, robj o, double target, const char msg) |
getLongDoubleFromObject | 從對象 o 中獲取 long double 值, 存入 target | int getLongDoubleFromObject(robj o, long double target) |
getLongDoubleFromObjectOrReply | 從對象 o 中獲取 long double 值, 存入 target; 若失敗返回給定信息 | int getLongDoubleFromObjectOrReply(redisClient c, robj o, long double target, const char msg) |
getLongLongFromObject | 從對象 o 中獲取 long long 值, 存入 target | int getLongLongFromObject(robj o, long long target) |
getLongLongFromObjectOrReply | 從對象 o 中獲取 long long 值, 存入 target; 若失敗返回給定信息 | int getLongLongFromObjectOrReply(redisClient c, robj o, long long target, const char msg) |
getLongFromObjectOrReply | 從對象 o 中獲取 long 值, 存入 target; 若失敗返回給定信息 | int getLongFromObjectOrReply(redisClient c, robj o, long target, const char msg) |
strEncoding | 返回給定 encoding 編碼的字符串表示 | char *strEncoding(int encoding) |
estimateObjectIdleTime | 計算給定對象的空閒時長 | unsigned long long estimateObjectIdleTime(robj *o) |
objectCommandLookup | OBJECT 命令獲取指定 key 的值對象, 不修改 lru | robj objectCommandLookup(redisClient c, robj *key) |
objectCommandLookupOrReply | OBJECT 命令獲取指定 key 的之對象, 不修改 lru; 若失敗返回給定信息 | robj objectCommandLookupOrReply(redisClient c, robj key, robj reply) |
objectCommand | OBJECT 命令 | void objectCommand(redisClient *c) |
函數 | 做用 | 備註 |
---|---|---|
listTypeTryConversion | 根據插入的 value 值, 看是否須要將鏈表 subject 從 ziplist 轉爲 linkedlist | void listTypeTryConversion(robj subject, robj value) |
listTypePush | 向鏈表 subject 頭部或尾部添加值 value | void listTypePush(robj subject, robj value, int where) |
listTypePop | 從鏈表 subject 頭部或尾部彈出節點 | robj listTypePop(robj subject, int where) |
listTypeLength | 獲取鏈表 subject 的長度 | unsigned long listTypeLength(robj *subject) |
listTypeInitIterator | 初始化鏈表迭代器 | listTypeIterator listTypeInitIterator(robj subject, long index, unsigned char direction) |
listTypeReleaseIterator | 釋放鏈表迭代器 li | void listTypeReleaseIterator(listTypeIterator *li) |
listTypeNext | 獲取迭代器當前指向的節點, 將其存入 entry | int listTypeNext(listTypeIterator li, listTypeEntry entry) |
listTypeGet | 返回 entry 結構保存的節點, 轉爲 robj 結構 | robj listTypeGet(listTypeEntry entry) |
listTypeInsert | 將 value 插入 entry 所在鏈表節點的前面或後面 | void listTypeInsert(listTypeEntry entry, robj value, int where) |
listTypeEqual | 判斷對象 o 與 entry 節點值是否相等 | int listTypeEqual(listTypeEntry entry, robj o) |
listTypeDelete | 刪除 entry 節點 | void listTypeDelete(listTypeEntry *entry) |
listTypeConvert | 將 subject 編碼轉換爲 linkedlist | void listTypeConvert(robj *subject, int enc) |
函數 | 做用 | 備註 |
---|---|---|
setTypeCreate | 根據 value 值建立集合 | robj setTypeCreate(robj value) |
setTypeAdd | 將 value 值添加到 subject 集合中 | int setTypeAdd(robj subject, robj value) |
setTypeRemove | 將 value 值從 setobj 集合中刪除 | int setTypeRemove(robj setobj, robj value) |
setTypeIsMember | 判斷 value 值是否在集合 subject 中 | int setTypeIsMember(robj subject, robj value) |
setTypeInitIterator | 建立指定 subject 集合的迭代器 | setTypeIterator setTypeInitIterator(robj subject) |
setTypeReleaseIterator | 釋放集合迭代器 | void setTypeReleaseIterator(setTypeIterator *si) |
setTypeNext | 獲取迭代器當前指向的節點, 存入 objele, 返回的對象沒有增長引用計數, 對 copy-on-write 友好 | int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele) |
setTypeNextObject | 獲取迭代器當前指向的節點, 老是返回一個新增的, 或者是引用計數增長的對象, 對 copy-on-write 非友好 | robj setTypeNextObject(setTypeIterator si) |
setTypeRandomElement | 從集合中隨機獲取一個元素, 若集合編碼是 intset, 存到 llele; 若編碼是 ht, 存到 objele | int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele) |
setTypeSize | 獲取集合的元素數量 | unsigned long setTypeSize(robj *subject) |
setTypeConvert | 將集合 setobj 的編碼轉換爲給定的 ht 編碼 | void setTypeConvert(robj *setobj, int enc) |
qsortCompareSetsByCardinality | 計算集合 s1 與集合 s2 的元素數量之差 | int qsortCompareSetsByCardinality(const void s1, const void s2) |
qsortCompareSetsByRevCardinality | 計算集合 s2 與集合 s1 的元素數量之差 | int qsortCompareSetsByRevCardinality(const void s1, const void s2) |
函數 | 做用 | 備註 |
---|---|---|
hashTypeTryConversion | 嘗試將 ziplist 編碼的 hash 對象轉換成 ht 編碼 | void hashTypeTryConversion(robj *o, robj ** argv, int start, int end) |
hashTypeTryObjectEncoding | 嘗試將 ht 編碼的鍵值對字符串對象分別進行編碼, 以節省內存 | void hashTypeTryObjectEncoding(robj *subject, robj o1, robj o2) |
hashTypeGetFromZiplist | 從 ziplist 編碼的 hash 中獲取指定 field 相對應的值 | int hashTypeGetFromZiplist(robj o, robj field, unsigned char ** vstr, unsigned int vlen, long long vll) |
hashTypeGetFromHashTable | 從 ht 編碼的 hash 中獲取指定 field 相對應的值 | int hashTypeGetFromZiplist(robj o, robj field, unsigned char **vstr, unsigned int vlen, long long vll) |
hashTypeGetObject | 從 hash 中獲取指定 field 的值, 返回 robj 對象 | robj hashTypeGetObject(robj o, robj *field) |
hashTypeExists | 判斷 hash 中指定 filed 是否存在 | int hashTypeExists(robj o, robj field) |
hashTypeSet | 將鍵值對添加到 hash 中, 若鍵已存在, 則使用新值替換舊值 | int hashTypeSet(robj o, robj field, robj *value) |
hashTypeDelete | 從 hash 中刪除指定 field 的鍵值對 | int hashTypeDelete(robj o, robj field) |
hashTypeLength | 返回 hash 中鍵值對數量 | unsigned long hashTypeLength(robj *o) |
hashTypeInitIterator | 建立 hash 迭代器 | hashTypeIterator hashTypeInitIterator(robj subject) |
hashTypeReleaseIterator | 釋放 hash 迭代器 | void hashTypeReleaseIterator(hashTypeIterator *hi) |
hashTypeNext | 獲取迭代器下個節點, 存入迭代器 | int hashTypeNext(hashTypeIterator *hi) |
hashTypeCurrentFromZiplist | 從 ziplist 編碼的 hash 中, 獲取迭代器當前指向的節點的 field 或 value 對象 | void hashTypeCurrentFromZiplist(hashTypeIterator *hi, int what, unsigned char **vstr, unsigned int vlen, long long vll) |
hashTypeCurrentFromHashTable | 從 ht 編碼的 hash 中, 獲取迭代器當前指向的節點的 field 或 value 對象 | void hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what, robj **dst) |
hashTypeCurrentObject | 獲取迭代器當前節點的 field 或 value 對象 | robj hashTypeCurrentObject(hashTypeIterator hi, int what) |
hashTypeLookupWriteOrCreate | 按 key 在數據庫中查找並返回相應 hash 對象, 若對象不存在, 建立新 hash 對象並返回 | robj hashTypeLookupWriteOrCreate(redisClient c, robj *key) |
hashTypeConvertZiplist | 將 ziplist 編碼的 hash 對象轉換成 ht 編碼 | void hashTypeConvertZiplist(robj *o, int enc) |
hashTypeConvert | 將 hash 對象 o 轉換成指定 enc 編碼, 目前僅支持將 ziplist 編碼轉換爲 ht 編碼 | void hashTypeConvert(robj *o, int enc) |