Grapehtml
DUMP key
序列化給定 key ,並返回被序列化的值,使用 RESTORE 命令能夠將這個值反序列化爲 Redis 鍵。
序列化生成的值有如下幾個特色:redis
序列化的值不包括任何生存時間信息。
可用版本:>= 2.6.0
時間複雜度:
查找給定鍵的複雜度爲 O(1) ,對鍵進行序列化的複雜度爲 O(N*M) ,其中 N 是構成 key 的 Redis 對象的數量,而 M 則是這些對象的平均大小。
若是序列化的對象是比較小的字符串,那麼複雜度爲 O(1) 。
返回值:若是 key 不存在,那麼返回 nil。不然,返回序列化以後的值。網絡
redis> SET greeting "hello, dumping world!" OK redis> DUMP greeting "\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde" redis> DUMP not-exists-key (nil)
咱們能夠看到,dump命令就是爲了序列化給定的key。那麼什麼是序列化呢?咱們看下序列化的定義:序列化(Serialization)將對象的狀態信息轉換爲能夠存儲或傳輸的形式的過程。在序列化期間,對象將其當前狀態寫入到臨時或持久性存儲區。之後,能夠經過從存儲區中讀取或反序列化對象的狀態,從新建立該對象。目的是爲了對象能夠跨平臺存儲,和進行網絡傳輸。
命令的使用很簡單,就是dump key,而dump一般和RESTORE配合使用,序列化與反序列化。若是想更多的瞭解序列化相關的知識,推薦閱讀:序列化理解起來很簡單。數據結構
首先咱們貼上源碼:app
/* DUMP keyname * DUMP is actually not used by Redis Cluster but it is the obvious * complement of RESTORE and can be useful for different applications. */ void dumpCommand(client *c) { robj *o, *dumpobj; rio payload; /* 檢查key是否存在 */ if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) { addReply(c,shared.nullbulk); return; } /*建立dump負載. */ createDumpPayload(&payload,o); /* 傳輸給客戶端 */ dumpobj = createObject(OBJ_STRING,payload.io.buffer.ptr); addReplyBulk(c,dumpobj); decrRefCount(dumpobj); return; }
接下來咱們慢慢分析。
Dump命令的核心是建立dump負載,因此咱們的核心就在於這個過程,首先咱們簡單描述下大體流程:首先檢查咱們要序列化的key是否存在,若存在則建立dump負載,而後傳輸給客戶端。函數
建立dump負載,這塊是dump命令的核心,具體的實現代碼以下:源碼分析
void createDumpPayload(rio *payload, robj *o) { unsigned char buf[2]; uint64_t crc; /* Serialize the object in a RDB-like format. It consist of an object type byte followed by the serialized object. This is understood by RESTORE. 以相似於rdb的格式序列化對象。它由對象類型字節和序列化對象組成。 */ rioInitWithBuffer(payload,sdsempty()); /*將給定的對象的類型寫到rdb中,失敗報錯*/ serverAssert(rdbSaveObjectType(payload,o)); /*將給定的對象寫到rdb中,失敗報錯*/ serverAssert(rdbSaveObject(payload,o)); /* Write the footer, this is how it looks like: ----------------+---------------------+---------------+ ... RDB payload | 2 bytes RDB version | 8 bytes CRC64 | ----------------+---------------------+---------------+ RDB version and CRC are both in little endian. /* RDB版本,被分爲兩個字節保存,表示爲0-65535 */ buf[0] = RDB_VERSION & 0xff; buf[1] = (RDB_VERSION >> 8) & 0xff; /*sdscatlen函數是擴展長度,並追加字符串 payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,buf,2); /* 計算CRC校驗碼,共8個字節 */ crc = crc64(0,(unsigned char*)payload->io.buffer.ptr, sdslen(payload->io.buffer.ptr)); /*對於目標機是大端字節序的機器,進行字節碼的轉換, 提供了16byte、32byte、64byte字節的轉換。 在intset\ziplist\zipmap三種數據結構中使用, 使得不一樣字節序機器生成的rdb文件格式都是統一的(小端字節序),便於兼容。*/ memrev64ifbe(&crc); payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,&crc,8);
}
最後生成的序列化對象格式就是下邊這個格式:
+-------------+---------------------+---------------+
| RDB payload | 2 bytes RDB version | 8 bytes CRC64 |
+-------------+---------------------+———————+ui
若是讀者有興趣,必定親手gdb試一試!!this