http://blog.csdn.net/lazybin/article/category/1255844
Redis(Remote Dictionary Server)是一種內存Key/Value數據庫。所有的Key/Value都是存放在內存中,如果內存不足,會將一些value swap到硬盤,但是Key始終都在內存中。Redis類似於Memcached。但是redis比memcached有更豐富的數據結構,還可以支持備份,數據持久化(snapshot和aof)。
具體的二者區別可以參考http://blog.csdn.net/gpcuster/article/details/5956555 。
下圖是一張是從網上獲取的關於redis內部的存儲結構(不知道原作者是誰了)。
最近在閱讀redis源代碼,決定將自己的一些理解記下來,用於備份和檢查。無奈技術水平很挫,如果有錯誤,還希望指正。代碼版本是2.6.2,代碼量比2.4.17大了很多。==!
- adlist.h 定義了一個雙鏈表結構。
- typedef struct listNode {
- struct listNode *prev;
- struct listNode *next;
- void *value;
- } listNode;
- typedef struct listIter {
- listNode *next;
- int direction;
- } listIter;
- typedef struct list {
- listNode *head;
- listNode *tail;
- void *(*dup)(void *ptr); //用於節點value的copy
- void (*free)(void *ptr); //用於節點value的釋放
- int (*match)(void *ptr, void *key); //節點value的比較
- unsigned long len; //鏈表的長度
- } list;
list *listInsertNode(list *list, listNode *old_node, void *value, int after) ;//根據after是否爲0來決定是在old_node節點之前(after == 0)還是之後(after != 0)
listNode *listIndex(list *list, long index);//返回鏈表中下標爲index的節點,0爲head節點,1爲head->next節點,以此類推。若index爲負數,則從後向前,-1爲tail節點,-2爲
tail->prev 節點以此類推。
list 數據結構不是太難理解~ 下文將會分析sds數據結構(作者自定義的字符串)
redis 源代碼之數據結構(2)--sds實現
1,sds(simple dynamic string)作爲redis作者自己實現的字符串類型,是redis的基本數據類型。
- typedef char *sds;
- struct sdshdr {
- int len;
- int free;
- char buf[];
- };
可以看到 sds本質上是一個char指針,內部存儲結構爲一個header+char*. len表示sds實際佔用的空間大小, free表示sds尚未使用的空間。buf指向實際的字符串內容。
sizeof(struct sdshsr)在32位操作系統下面是8,redis作者沒有用char *buf,是不是覺得這樣一個頭部就可以節約4字節內存?char buf[]被gcc編譯器理解爲動態數組了,而且buf變量只能放在結構體最後位置。否則報錯。
2, 關於sds的操作
1)創建sds
sds.c有三個函數用於創建sds
- sds sdsnewlen(const void *init, size_t initlen);//主要的創建函數
- sds sdsnew(const char *init);//這個函數實際上調用的sdsnewlen,initlen問 字符串init的大小(不包含最後的‘\0’)
- sds sdsempty();//同調用sdsnewlen,只不過initlen爲0
sdsnewlen的具體代碼
- sds sdsnewlen(const void *init, size_t initlen) {
- struct sdshdr *sh;
- if (init) {
- sh = zmalloc(sizeof(struct sdshdr)+initlen+1); //一個sds真正的佔用空間爲頭部大小+字符串長度
- } else {
- sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
- }
- if (sh == NULL) return NULL;
- sh->len = initlen; //此處的len,沒有把'\0‘計算在內
- sh->free = 0;
- if (initlen && init)
- memcpy(sh->buf, init, initlen);
- sh->buf[initlen] = '\0';
- return (char*)sh->buf; //返回的指針指向真正字符串內容,而不是返回頭部指針,這樣用戶之需要關心真正的內容就行,不需要管理頭部
- }
- sds mysds = sdsnewlen("redis", 5);
那麼如何獲取頭部信息呢,比如說我想獲取sds的長度(buf長度)
- static inline size_t sdslen(const sds s) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));//往前偏移
- return sh->len;
- }
2)sds釋放
- void sdsfree(sds s) {
- if (s == NULL) return;
- zfree(s-sizeof(struct sdshdr));
- }
3)sds其他操作這裏就不再敘述,基本上常見的字符串的操作都可以找到。