[TOC]html
引用:Redis詳解(四)------ redis的底層數據結構redis
判斷值類型:
object encoding keyname
算法
127.0.0.1:6379> set k1 str
OK
127.0.0.1:6379> set k2 123
OK
127.0.0.1:6379> Object encoding k1
"embstr"
127.0.0.1:6379> Object encoding k2
"int"
127.0.0.1:6379> lpush list1 1 2 3
(integer) 3
127.0.0.1:6379> Object encoding list1
"quicklist"
127.0.0.1:6379> hset testhash key1 009
(integer) 1
127.0.0.1:6379> object encoding testhash
"ziplist"
127.0.0.1:6379> hset testhash key2 00ososkskkalalkskskaaakasmasd,jansm,namsnasnda,msn,akdwj,kjallllllaaaaassjjjjjjjjacacascascascmnascaksc,ascmascna,klna,cksa,cksans,can,scamcs9
(integer) 1
127.0.0.1:6379> object encoding testhash
"hashtable"
127.0.0.1:6379>
複製代碼
數據結構數據庫
數據結構 | 定義常量 | 值 |
---|---|---|
整數類型 | REDIS_ENCODING_INT | "int" |
embstr字符串類型 | REDIS_ENCODING_EMBSTR | "embstr" |
簡單動態字符串 | REDIS_ENCODING_RAW | "raw" |
字典類型 | REDIS_ENCODING_HT | "hashtable" |
雙端鏈表 | REDIS_ENCODING_LINKEDLIST | "linkedlist" |
壓縮列表 | REDIS_ENCODING_ZIPLIST | "ziplist" |
整數集合 | REDIS_ENCODING_INTSET | "intset" |
跳錶和字典 | REDIS_ENCODING_SKIPLIST | "skiplist" |
對應關係數組
1. string ==> raw|embstr|int
2. list ==> quicklist
3. hash ==> ziplist|hashtable
4. set ==> intset|hashtable
5. zset ==> ziplist|skiplist
6. stream => stream
複製代碼
struct sdshdr{
//記錄buf數組中已使用字節的數量
//等於 SDS 保存字符串的長度
int len;
//記錄 buf 數組中未使用字節的數量
int free;
//字節數組,用於保存字符串
char buf[];
}
複製代碼
SDS保存的字符串結構圖示: 安全
常數複雜度獲取字符串長度bash
杜絕緩衝區溢出數據結構
減小修改字符串的內存從新分配次數函數
二進制安全ui
兼容部分C字符串函數
//鏈表節點
typedef struct listNode{
//前置節點
struct listNode *prev;
//後置節點
struct listNode *next;
//節點的值
void *value;
}listNode
複製代碼
經過多個 listNode 結構就能夠組成鏈表,這是一個雙端鏈表,Redis還提供了操做鏈表的數據結構:
typedef struct list{
//表頭節點
listNode *head;
//表尾節點
listNode *tail;
//鏈表所包含的節點數量
unsigned long len;
//節點值複製函數
void (*free) (void *ptr);
//節點值釋放函數
void (*free) (void *ptr);
//節點值對比函數
int (*match) (void *ptr,void *key);
}list;
複製代碼
字典又稱爲符號表或者關聯數組、或映射(map),是一種用於保存鍵值對的抽象數據結構。字典中的每個鍵 key 都是惟一的,經過 key 能夠對值來進行查找或修改。 - - Redis 的字典使用哈希表做爲底層實現
typedef struct dictht{
//哈希表數組
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表大小掩碼,用於計算索引值
//老是等於 size-1
unsigned long sizemask;
//該哈希表已有節點的數量
unsigned long used;
}dictht
複製代碼
哈希表是由數組 table 組成,table 中每一個元素都是指向 dict.h/dictEntry 結構,dictEntry 結構定義以下:
typedef struct dictEntry{
//鍵
void *key;
//值
union{
void *val;
uint64_tu64;
int64_ts64;
}v;
//指向下一個哈希表節點,造成鏈表
struct dictEntry *next;
}dictEntry
複製代碼
key 用來保存鍵,val 屬性用來保存值,值能夠是一個指針,也能夠是uint64_t整數,也能夠是int64_t整數。
注意這裏還有一個指向下一個哈希表節點的指針,咱們知道哈希表最大的問題是存在哈希衝突,如何解決哈希衝突,有開放地址法和鏈地址法。這裏採用的即是鏈地址法,經過next這個指針能夠將多個哈希值相同的鍵值對鏈接在一塊兒,用來解決哈希衝突。
#一、使用字典設置的哈希函數,計算鍵 key 的哈希值
hash = dict->type->hashFunction(key);
#二、使用哈希表的sizemask屬性和第一步獲得的哈希值,計算索引值
index = hash & dict->ht[x].sizemask;
複製代碼
跳躍表(skiplist)是一種有序數據結構,它經過在每一個節點中維持多個指向其它節點的指針,從而達到快速訪問節點的目的。
//表節點定義
typedef struct zskiplistNode {
//層
struct zskiplistLevel{
//前進指針
struct zskiplistNode *forward;
//跨度
unsigned int span;
}level[];
//後退指針
struct zskiplistNode *backward;
//分值
double score;
//成員對象
robj *obj;
} zskiplistNode
複製代碼
多個跳躍表節點構成了一個跳躍表
typedef struct zskiplist{
//表頭節點和表尾節點
structz skiplistNode *header, *tail;
//表中節點的數量
unsigned long length;
//表中層數最大的節點的層數
int level;
}zskiplist;
複製代碼
//列表節點
typedef struct ziplistNode{
// 記錄壓縮列表前一個字節的長度.
int previous_entry_length;
// 節點的content的內容類型以及長度.encoding類型一共有兩種,一種字節數組一種是整數,encoding區域長度爲1字節、2字節或者5字節長。
buf encoding;
// 節點的內容,節點內容類型和長度由encoding決定。
buf content;
}
// 壓縮表
typedef struct ziplist{
//表頭節點和表尾節點
structz ziplistNode entryX;
//表中節點的數量
unsigned long length;
//表中層數最大的節點的層數
int zlbytes;
int zltail;
int zlen;
int zlend:
}ziplist;
複製代碼
結構圖
1.保存的元素數量小於128;
2.保存的全部元素長度都小於64字節。
不能知足上面兩個條件的使用 skiplist 編碼。以上兩個條件也能夠經過Redis配置文件zset-max-ziplist-entries 選項和 zset-max-ziplist-value 進行修改。
整數集合intset是Redis用於保存整數值的集合抽象數據類型,他能夠保存類型爲int16_t,int32_t或者int64_t的整數值,而且保證集合中不會出現重複元素。
typedef struct intset{
//編碼方式
uint32_t encoding;
//集合包含的元素數量
uint32_t length;
//保存元素的數組
int8_t contents[];
}intset;
複製代碼
整數集合的每個元素都是contents數組的一個數據項,他們按照從大到小的順序排列,而且不包含任何重複項 length屬性記錄來contents數組的大小 須要注意的是雖然contents數組聲明爲int_8類型,可是實際上contents數組並不保存任何int_8類型的值,其真正類型由encoding來決定。