redis原始碼分析之zipmap.c
/**
* 建立空zipmap
* @return
*/
/* Create a new empty zipmap. */
unsigned char *zipmapNew(void) {
unsigned char *zm = zmalloc(2);
zm[0] = 0; /* Length */
zm[1] = ZIPMAP_END;
return zm;
}
/**
* 讀取zipmap元素的長度(1位元組或者5位元組,五位元組時,第一個位元組為標誌位)
* @param p
* @return
*/
/* Decode the encoded length pointed by 'p' */
static unsigned int zipmapDecodeLength(unsigned char *p) {
unsigned int len = *p;
if (len < ZIPMAP_BIGLEN) return len;
memcpy(&len,p+1,sizeof(unsigned int));
memrev32ifbe(&len);
return len;
}
/**
* 計算編碼zipmap value長度所需要的位元組數,並且儲存在p中,若p為空則只返回佔用位元組數
* @param p
* @param len
* @return
*/
/* Encode the length 'l' writing it in 'p'. If p is NULL it just returns
* the amount of bytes required to encode such a length. */
static unsigned int zipmapEncodeLength(unsigned char *p, unsigned int len) {
if (p == NULL) {
return ZIPMAP_LEN_BYTES(len);
} else {
if (len < ZIPMAP_BIGLEN) {
p[0] = len;
return 1;
} else {
p[0] = ZIPMAP_BIGLEN;
memcpy(p+1,&len,sizeof(len));
memrev32ifbe(p+1);
return 1+sizeof(len);
}
}
}
/**
* zipmap查詢key,如果totlen指標不為空,則返回zip整個長度
* @param zm
* @param key
* @param klen
* @param totlen
* @return
*/
/* Search for a matching key, returning a pointer to the entry inside the
* zipmap. Returns NULL if the key is not found.
*
* If NULL is returned, and totlen is not NULL, it is set to the entire
* size of the zimap, so that the calling function will be able to
* reallocate the original zipmap to make room for more entries. */
static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) {
unsigned char *p = zm+1, *k = NULL;
unsigned int l,llen;
while(*p != ZIPMAP_END) {
unsigned char free;
/* Match or skip the key */
l = zipmapDecodeLength(p);
llen = zipmapEncodeLength(NULL,l);
if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) {
/* Only return when the user doesn't care
* for the total length of the zipmap. */
if (totlen != NULL) {
k = p;
} else {
return p;
}
}
//zmlen–len–“foo”–len–free–“bar”–len–“hello”–len–free–“world”-end
//跳過key
p += llen+l;
//跳過value
/* Skip the value as well */
l = zipmapDecodeLength(p);
p += zipmapEncodeLength(NULL,l);
free = p[0];
p += l+1+free; /* +1 to skip the free byte */
}
if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1;//算上end佔用的一個位元組
return k;
}
/**
* 計算zipmap entry需要的長度
* @param klen
* @param vlen
* @return
*/
static unsigned long zipmapRequiredLength(unsigned int klen, unsigned int vlen) {
unsigned int l;
l = klen+vlen+3;
if (klen >= ZIPMAP_BIGLEN) l += 4;
if (vlen >= ZIPMAP_BIGLEN) l += 4;
return l;
}
/**
* zipmap entry key佔用的位元組數
* @param p
* @return
*/
/* Return the total amount used by a key (encoded length + payload) */
static unsigned int zipmapRawKeyLength(unsigned char *p) {
unsigned int l = zipmapDecodeLength(p);
return zipmapEncodeLength(NULL,l) + l;
}
/**
* zipmap entry value佔用的位元組數,包括空閒長度
* @param p
* @return
*/
/* Return the total amount used by a value
* (encoded length + single byte free count + payload) */
static unsigned int zipmapRawValueLength(unsigned char *p) {
unsigned int l = zipmapDecodeLength(p);
unsigned int used;
used = zipmapEncodeLength(NULL,l);
//p[used]為空閒長度
used += p[used] + 1 + l;
return used;
}
/**
* 計算zipmap entry的位元組數
* @param p
* @return
*/
/* If 'p' points to a key, this function returns the total amount of
* bytes used to store this entry (entry = key + associated value + trailing
* free space if any). */
static unsigned int zipmapRawEntryLength(unsigned char *p) {
unsigned int l = zipmapRawKeyLength(p);
return l + zipmapRawValueLength(p+l);
}
/**
* zipmap 空間重分配
* @param zm
* @param len
* @return
*/
static inline unsigned char *zipmapResize(unsigned char *zm, unsigned int len) {
zm = zrealloc(zm, len);
zm[len-1] = ZIPMAP_END;
return zm;
}
/**
* zipmap設定或者更新entry
* @param zm
* @param key
* @param klen
* @param val
* @param vlen
* @param update
* @return
*/
/* Set key to value, creating the key if it does not already exist.
* If 'update' is not NULL, *update is set to 1 if the key was
* already preset, otherwise to 0. */
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) {
unsigned int zmlen, offset;
unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen);
unsigned int empty, vempty;
unsigned char *p;
freelen = reqlen;
if (update) *update = 0;
p = zipmapLookupRaw(zm,key,klen,&zmlen);
if (p == NULL) {
/* Key not found: enlarge */
zm = zipmapResize(zm, zmlen+reqlen);
p = zm+zmlen-1;
zmlen = zmlen+reqlen;
/* Increase zipmap length (this is an insert) */
if (zm[0] < ZIPMAP_BIGLEN) zm[0]++;//大於等於254就不起作用了
} else {
/* Key found. Is there enough space for the new value? */
/* Compute the total length: */
if (update) *update = 1;
freelen = zipmapRawEntryLength(p);
if (freelen < reqlen) {
/* Store the offset of this key within the current zipmap, so
* it can be resized. Then, move the tail backwards so this
* pair fits at the current position. */
offset = p-zm;
zm = zipmapResize(zm, zmlen-freelen+reqlen);
p = zm+offset;
/* The +1 in the number of bytes to be moved is caused by the
* end-of-zipmap byte. Note: the *original* zmlen is used. */
//移動末尾位元組位置到p+reqlen,在擴容的時候已經重置end,所以移動的時候少一個位元組
memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
zmlen = zmlen-freelen+reqlen;
freelen = reqlen;
}
}
/* We now have a suitable block where the key/value entry can
* be written. If there is too much free space, move the tail
* of the zipmap a few bytes to the front and shrink the zipmap,
* as we want zipmaps to be very space efficient. */
//如果reqlen小的話,並且達到閾值(4位元組)的話,進行縮容操作
empty = freelen-reqlen;
if (empty >= ZIPMAP_VALUE_MAX_FREE) {
/* First, move the tail <empty> bytes to the front, then resize
* the zipmap to be <empty> bytes smaller. */
offset = p-zm;
memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
zmlen -= empty;
zm = zipmapResize(zm, zmlen);
p = zm+offset;
vempty = 0;
} else {
//如果不縮容的話,需要記錄free空間佔用
vempty = empty;
}
/* Just write the key + value and we are done. */
/* Key: */
p += zipmapEncodeLength(p,klen);
memcpy(p,key,klen);
p += klen;
/* Value: */
p += zipmapEncodeLength(p,vlen);
*p++ = vempty;
memcpy(p,val,vlen);
return zm;
}
/**
* zipmap 刪除指定key的entry
* @param zm
* @param key
* @param klen
* @param deleted
* @return
*/
/* Remove the specified key. If 'deleted' is not NULL the pointed integer is
* set to 0 if the key was not found, to 1 if it was found and deleted. */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {
unsigned int zmlen, freelen;
unsigned char *p = zipmapLookupRaw(zm,key,klen,&zmlen);
if (p) {
freelen = zipmapRawEntryLength(p);
memmove(p, p+freelen, zmlen-((p-zm)+freelen+1));
zm = zipmapResize(zm, zmlen-freelen);
/* Decrease zipmap length */
if (zm[0] < ZIPMAP_BIGLEN) zm[0]--;//如果元素個數為254個,則不做修改
if (deleted) *deleted = 1;
} else {
if (deleted) *deleted = 0;
}
return zm;
}
/**
* zipmap 跳過zipmap len
* @param zm
* @return
*/
/* Call before iterating through elements via zipmapNext() */
unsigned char *zipmapRewind(unsigned char *zm) {
return zm+1;
}
/**
* zipmap next元素
* @param zm
* @param key
* @param klen
* @param value
* @param vlen
* @return
*/
/* This function is used to iterate through all the zipmap elements.
* In the first call the first argument is the pointer to the zipmap + 1.
* In the next calls what zipmapNext returns is used as first argument.
* Example:
*
* unsigned char *i = zipmapRewind(my_zipmap);
* while((i = zipmapNext(i,&key,&klen,&value,&vlen)) != NULL) {
* printf("%d bytes key at $p\n", klen, key);
* printf("%d bytes value at $p\n", vlen, value);
* }
*/
unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen) {
if (zm[0] == ZIPMAP_END) return NULL;
if (key) {
*key = zm;
*klen = zipmapDecodeLength(zm);
*key += ZIPMAP_LEN_BYTES(*klen);
}
zm += zipmapRawKeyLength(zm);
if (value) {
*value = zm+1;
*vlen = zipmapDecodeLength(zm);
*value += ZIPMAP_LEN_BYTES(*vlen);
}
zm += zipmapRawValueLength(zm);
return zm;
}
/**
* zipmap 獲取指定key的value
* @param zm
* @param key
* @param klen
* @param value
* @param vlen
* @return
*/
/* Search a key and retrieve the pointer and len of the associated value.
* If the key is found the function returns 1, otherwise 0. */
int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen) {
unsigned char *p;
if ((p = zipmapLookupRaw(zm,key,klen,NULL)) == NULL) return 0;
p += zipmapRawKeyLength(p);
*vlen = zipmapDecodeLength(p);
*value = p + ZIPMAP_LEN_BYTES(*vlen) + 1;
return 1;
}
/**
* zipmap 判斷元素是否存在
* @param zm
* @param key
* @param klen
* @return
*/
/* Return 1 if the key exists, otherwise 0 is returned. */
int zipmapExists(unsigned char *zm, unsigned char *key, unsigned int klen) {
return zipmapLookupRaw(zm,key,klen,NULL) != NULL;
}
/**
* zipmap獲取zipmap長度,如果超過了長度則重置長度(zipmap整個api中其實不強依賴於這個位元組,可能只是為了判別要轉換為dict的閾值)
* @param zm
* @return
*/
/* Return the number of entries inside a zipmap */
unsigned int zipmapLen(unsigned char *zm) {
unsigned int len = 0;
if (zm[0] < ZIPMAP_BIGLEN) {
len = zm[0];
} else {
unsigned char *p = zipmapRewind(zm);
while((p = zipmapNext(p,NULL,NULL,NULL,NULL)) != NULL) len++;
/* Re-store length if small enough */
if (len < ZIPMAP_BIGLEN) zm[0] = len;
}
return len;
}
/**
* zipmap總佔用位元組數
* @param zm
* @return
*/
/* Return the raw size in bytes of a zipmap, so that we can serialize
* the zipmap on disk (or everywhere is needed) just writing the returned
* amount of bytes of the C array starting at the zipmap pointer. */
size_t zipmapBlobLen(unsigned char *zm) {
unsigned int totlen;
zipmapLookupRaw(zm,NULL,0,&totlen);
return totlen;
}
#ifdef REDIS_TEST
static void zipmapRepr(unsigned char *p) {
unsigned int l;
printf("{status %u}",*p++);
while(1) {
if (p[0] == ZIPMAP_END) {
printf("{end}");
break;
} else {
unsigned char e;
l = zipmapDecodeLength(p);
printf("{key %u}",l);
p += zipmapEncodeLength(NULL,l);
if (l != 0 && fwrite(p,l,1,stdout) == 0) perror("fwrite");
p += l;
l = zipmapDecodeLength(p);
printf("{value %u}",l);
p += zipmapEncodeLength(NULL,l);
e = *p++;
if (l != 0 && fwrite(p,l,1,stdout) == 0) perror("fwrite");
p += l+e;
if (e) {
printf("[");
while(e--) printf(".");
printf("]");
}
}
}
printf("\n");
}
#define UNUSED(x) (void)(x)
int zipmapTest(int argc, char *argv[]) {
unsigned char *zm;
UNUSED(argc);
UNUSED(argv);
zm = zipmapNew();
zm = zipmapSet(zm,(unsigned char*) "name",4, (unsigned char*) "foo",3,NULL);
zm = zipmapSet(zm,(unsigned char*) "surname",7, (unsigned char*) "foo",3,NULL);
zm = zipmapSet(zm,(unsigned
相關推薦
redis原始碼分析之zipmap.c
/**
* 建立空zipmap
* @return
*/
/* Create a new empty zipmap. */
unsigned char *zipmapNew(void) {
unsigned char *zm = zmalloc(2
redis原始碼分析之intset.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intset.h"
#include "zmalloc.h"
#include "end
Open-iscs原始碼分析之---iscsiadm.c
login處理...
main(int argc, char **argv)
{
......
printf("anycom: iscsiadmin.c 2332");
rc = exec_node_op(op, do_login, do_logout,
YOLO原始碼分析之data.c
darknet裡樣本的儲存是以如下形式進行排列的
flag | class_info | box_info
flag為0或者1,表示有沒有物體
class_info表示類別資訊,其長度是num_class
box_info表示標註資訊,其長度是5(x, y, w, h, o
redis原始碼分析與思考(十七)——有序集合型別的命令實現(t_zset.c)
有序集合是集合的延伸,它儲存著集合元素的不可重複性,但不同的是,它是有序的,它利用每一個元素的分數來作為有序集合的排序依據,現在列出有序集合的命令:
有序集合命令
命令
對應操作
時
redis原始碼分析與思考(十六)——集合型別的命令實現(t_set.c)
集合型別是用來儲存多個字串的,與列表型別不一樣,集合中不允許有重複的元素,也不能以索引的方式來通過下標獲取值,集合中的元素還是無序的。在普通的集合上增刪查改外,集合型別還實現了多個集合的取交集、並集、差集,集合的命令如下表所示:
集合命
redis原始碼分析與思考(十五)——雜湊型別的命令實現(t_hash.c)
雜湊型別又叫做字典,在redis中,雜湊型別本身是一個鍵值對,而雜湊型別裡面也存貯著鍵值對,其對應關係是,每個雜湊型別的值對應著一個鍵值對或多對鍵值對,如圖所示:
雜湊型別命令
命令
對應操
redis原始碼分析與思考(十四)——列表型別的命令實現(t_list.c)
列表型別是用來存貯多個字串物件的結構。一個列表可以存貯232-1個元素,可以對列表兩端進行插入(push)、彈出(pop),還可以獲取指定範圍內的元素列表、獲取指定索引的元素等等,它可以靈活的充當棧和佇列的角色。下面列出列表的命令:
列
redis原始碼分析與思考(十三)——字串型別的命令實現(t_string.c)
在對字串操作的命令中,主要有增加刪查該、批處理操作以及編碼的轉換命令,現在列出對字串物件操作的主要常用命令:
常用命令表
命令
對應操作
時間複雜度
redis原始碼分析與思考(十七)——有序集合型別的命令實現(t_set.c)
有序集合是集合的延伸,它儲存著集合元素的不可重複性,但不同的是,它是有序的,它利用每一個元素的分數來作為有序集合的排序依據,現在列出有序集合的命令:
有序集合命令
命令
對應操作
時間複
Android Wi-Fi原始碼分析之WifiService操作Wi-Fi(一):分析Wifi.c中的wifi_load_driver()函式
Wi-Fi原始碼分析之WifiService操作Wi-Fi(一)
分析Wifi.c中的wifi_load_driver()函式
int wifi_load_driver()
{
AL
ghostscript原始碼分析之 scan_token()函式 (詞法分析器iscan.c)
scan_token()函式很重要,ghostscript寫得比較瑣碎難懂,裡面有些有英文解釋。
我只對我關注的部分加了些中文註釋。當然不是所有的都理解了。但是功能還是清楚了的,像某些函式介面。
如果讓我寫的話,我一定比他寫得更清晰。哈哈,當然他的scan_token基本的框架
設計還是
STL原始碼分析之hash表(gnu-c++ 2.9)
1、基本概念
關於hash表的概念這裡就不再多說,hash表的變化一般都在雜湊函式和退避方法上。STL採用的是開鏈法,即每個hash桶裡面維持一個連結串列,hash函式計算出位置後,就將節點插入該位置的連結串列上,因此,底層實現為hash表的容器,迭代器的實現
Redis原始碼分析(三十五)--- redis.c服務端的實現分析(2)
在Redis服務端的程式碼量真的是比較大,如果一個一個API的學習怎麼實現,無疑是一種效率很低的做法,所以我今天對服務端的實現程式碼的學習,重在他的執行流程上,而對於他的模組設計在上一篇中我已經分析過了,不明白的同學可以接著看上篇。所以我學習分析redis服務
HotSpot原始碼分析之C++物件的記憶體佈局
HotSpot採用了OOP-Klass模型來描述Java類和物件。OOP(Ordinary Object Pointer)指的是普通物件指標,而Klass用來描述物件的具體型別。為了更好理解這個模型,首先要介紹一下C++的記憶體物件模型和虛擬函式。
1、C++類物件的記憶體佈局
我們使用Visual Stud
Spark原始碼分析之Spark Shell(上)
https://www.cnblogs.com/xing901022/p/6412619.html
文中分析的spark版本為apache的spark-2.1.0-bin-hadoop2.7。
bin目錄結構:
-rwxr-xr-x. 1 bigdata bigdata 1089 Dec
Netty 原始碼分析之拆包器的奧祕
為什麼要粘包拆包
為什麼要粘包
首先你得了解一下TCP/IP協議,在使用者資料量非常小的情況下,極端情況下,一個位元組,該TCP資料包的有效載荷非常低,傳遞100位元組的資料,需要100次TCP傳送,100次ACK,在應用及時性要求不高的情況下,將這100個有效資料拼接成一個數據包,那會縮短到一個TCP資
Android原始碼分析之為什麼在onCreate() 和 onResume() 獲取不到 View 的寬高
轉載自:https://www.jianshu.com/p/d7ab114ac1f7
先來看一段很熟悉的程式碼,可能在最開始接觸安卓的時候,大部分人都寫過的一段程式碼;即嘗試在 onCreate() 和 onResume() 方法中去獲取某個 View 的寬高資訊:
但是列印輸出後,我們會發
netty原始碼分析之服務端啟動
ServerBootstrap與Bootstrap分別是netty中服務端與客戶端的引導類,主要負責服務端與客戶端初始化、配置及啟動引導等工作,接下來我們就通過netty原始碼中的示例對ServerBootstrap與Bootstrap的原始碼進行一個簡單的分析。首先我們知道這兩個類都繼承自AbstractB
SNMP原始碼分析之(一)配置檔案部分
snmpd.conf想必不陌生。在程序啟動過程中會去讀取配置檔案中各個配置。其中幾個引數需要先知道是幹什麼的:
token:配置檔案的每行的開頭,例如
group MyROGroup v1 readSec
這行token的引數是group。