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