能进外国网站看视频的浏览器,深圳网站建设服务哪便宜,中医药文化建设网站,wordpress开启评论验证码文章目录RBD文件载入RDB文件分析源码分析核心代码rdb文件写入rdb写入关键函数rdbSaveObjectTyperdbSaveStringObjectRawrdbSaveLongLongAsStringObject为避免数据丢失。将redis中的数据保存到磁盘中#xff0c;避免数据意外丢失。 RBD文件载入 在redis启动时检测是否有rdb文件…
文章目录RBD文件载入RDB文件分析源码分析核心代码rdb文件写入rdb写入关键函数rdbSaveObjectTyperdbSaveStringObjectRawrdbSaveLongLongAsStringObject为避免数据丢失。将redis中的数据保存到磁盘中避免数据意外丢失。 RBD文件载入 在redis启动时检测是否有rdb文件有的话会自动载入。 命令作用save阻塞服务器进程知道rbd文件创建完成bgsavefork子进程由子进程负责创建RDB文件
RDB文件分析 [rootpython redis-4.0.14]# od -c dump.rdb
0000000 R E D I S 0 0 0 8 372 \t r e d i s
0000020 - v e r 006 4 . 0 . 1 4 372 \n r e d
0000040 i s - b i t s 300 372 005 c t i m e
0000060 302 212 \b 331 ] 372 \b u s e d - m e m 302
0000100 210 \0 \f \0 372 \f a o f - p r e a m b
0000120 l e 300 \0 376 \0 373 001 \0 \0 004 n a m e 300
0000140 { 377 8 033 _ 360 I 223 254 343
0000152
[rootpython redis-4.0.14]# redis-cli
127.0.0.1:6379 flushall
OK
127.0.0.1:6379 set name xxxx
OK
127.0.0.1:6379 save
OK
127.0.0.1:6379 exit
[rootpython redis-4.0.14]# od -c dump.rdb
0000000 R E D I S 0 0 0 8 372 \t r e d i s
0000020 - v e r 006 4 . 0 . 1 4 372 \n r e d
0000040 i s - b i t s 300 372 005 c t i m e
0000060 302 b | 333 ] 372 \b u s e d - m e m 302
0000100 0 356 \f \0 372 \f a o f - p r e a m b
0000120 l e 300 \0 376 \0 373 001 \0 \0 004 n a m e 004
0000140 x x x x 377 314 221 277 [ 223 026 $
00001550000000 R E D I S 0 0 0 8 372 \t r e d i s 1、五个字节的REDIS 2、四个字节版本号 3、 一个字节的eof常量 4、八个字节校验和 004 n a m e 004 0000140 x x x x 377 314 221 277 [ 223 026 $ 004是key的长度 377 314 221 277 [ 223 026 $ 八字节长的校验和
源码分析 Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success 将数据库保存到磁盘上。 保存成功返回 REDIS_OK 出错/失败返回 REDIS_ERR 。 int rdbSave(char *filename) {// 创建临时文件snprintf(tmpfile,256,temp-%d.rdb, (int) getpid());fp fopen(tmpfile,w);if (!fp) {redisLog(REDIS_WARNING, Failed opening .rdb for saving: %s,strerror(errno));return REDIS_ERR;}// 初始化 I/OrioInitWithFile(rdb,fp);// 设置校验和函数if (server.rdb_checksum)rdb.update_cksum rioGenericUpdateChecksum;// 写入 RDB 版本号snprintf(magic,sizeof(magic),REDIS%04d,REDIS_RDB_VERSION);if (rdbWriteRaw(rdb,magic,9) -1) goto werr;// 遍历所有数据库for (j 0; j server.dbnum; j) {// 指向数据库redisDb *db server.dbj;// 指向数据库键空间dict *d db-dict;// 跳过空数据库if (dictSize(d) 0) continue;// 创建键空间迭代器di dictGetSafeIterator(d);if (!di) {fclose(fp);return REDIS_ERR;}/* Write the SELECT DB opcode** 写入 DB 选择器*/if (rdbSaveType(rdb,REDIS_RDB_OPCODE_SELECTDB) -1) goto werr;if (rdbSaveLen(rdb,j) -1) goto werr;/* Iterate this DB writing every entry** 遍历数据库并写入每个键值对的数据*/while((de dictNext(di)) ! NULL) {sds keystr dictGetKey(de);robj key, *o dictGetVal(de);long long expire;// 根据 keystr 在栈中创建一个 key 对象initStaticStringObject(key,keystr);// 获取键的过期时间expire getExpire(db,key);// 保存键值对数据if (rdbSaveKeyValuePair(rdb,key,o,expire,now) -1) goto werr;}dictReleaseIterator(di);}di NULL; /* So that we dont release it again on error. *//* EOF opcode** 写入 EOF 代码*/if (rdbSaveType(rdb,REDIS_RDB_OPCODE_EOF) -1) goto werr;/* CRC64 checksum. It will be zero if checksum computation is disabled, the* loading code skips the check in this case.** CRC64 校验和。** 如果校验和功能已关闭那么 rdb.cksum 将为 0 * 在这种情况下 RDB 载入时会跳过校验和检查。*/cksum rdb.cksum;memrev64ifbe(cksum);rioWrite(rdb,cksum,8);/* Make sure data will not remain on the OSs output buffers */// 冲洗缓存确保数据已写入磁盘if (fflush(fp) EOF) goto werr;if (fsync(fileno(fp)) -1) goto werr;if (fclose(fp) EOF) goto werr;/* Use RENAME to make sure the DB file is changed atomically only* if the generate DB file is ok.** 使用 RENAME 原子性地对临时文件进行改名覆盖原来的 RDB 文件。*/if (rename(tmpfile,filename) -1) {redisLog(REDIS_WARNING,Error moving temp DB file on the final destination: %s, strerror(errno));unlink(tmpfile);return REDIS_ERR;}// 写入完成打印日志redisLog(REDIS_NOTICE,DB saved on disk);// 清零数据库脏状态server.dirty 0;// 记录最后一次完成 SAVE 的时间server.lastsave time(NULL);// 记录最后一次执行 SAVE 的状态server.lastbgsave_status REDIS_OK;return REDIS_OK;werr:// 关闭文件fclose(fp);// 删除文件unlink(tmpfile);redisLog(REDIS_WARNING,Write error saving DB on disk: %s, strerror(errno));if (di) dictReleaseIterator(di);return REDIS_ERR;
}核心代码
// 遍历所有数据库for (j 0; j server.dbnum; j) {// 创建键空间迭代器di dictGetSafeIterator(d);if (!di) {fclose(fp);return REDIS_ERR;}/* Write the SELECT DB opcode** 写入 DB 选择器*//* * 遍历数据库并写入每个键值对的数据*/while((de dictNext(di)) ! NULL) {sds keystr dictGetKey(de);robj key, *o dictGetVal(de);long long expire;// 根据 keystr 在栈中创建一个 key 对象initStaticStringObject(key,keystr);// 获取键的过期时间expire getExpire(db,key);// 保存键值对数据if (rdbSaveKeyValuePair(rdb,key,o,expire,now) -1) goto werr;}dictReleaseIterator(di);}获取键值和键
237 // 计算给定键的哈希值
238 #define dictHashKey(d, key) (d)-type-hashFunction(key)
239 // 返回获取给定节点的键
240 #define dictGetKey(he) ((he)-key)
241 // 返回获取给定节点的值
242 #define dictGetVal(he) ((he)-v.val)rdb文件写入 891 int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,892 long long expiretime, long long now)893 {894 /* Save the expire time895 *896 * 保存键的过期时间897 */898 if (expiretime ! -1) {899 /* If this key is already expired skip it900 *901 * 不写入已经过期的键902 */903 if (expiretime now) return 0;904905 if (rdbSaveType(rdb,REDIS_RDB_OPCODE_EXPIRETIME_MS) -1) return -1;906 if (rdbSaveMillisecondTime(rdb,expiretime) -1) return -1;907 }908909 /* Save type, key, value910 *911 * 保存类型键值912 */913 if (rdbSaveObjectType(rdb,val) -1) return -1;914 if (rdbSaveStringObject(rdb,key) -1) return -1;915 if (rdbSaveObject(rdb,val) -1) return -1;916917 return 1;918 }rdb写入关键函数rdbSaveObjectType 655 /* Save the object type of object o.656 *657 * 将对象 o 的类型写入到 rdb 中658 */659 int rdbSaveObjectType(rio *rdb, robj *o) {660661 switch (o-type) {662663 case REDIS_STRING:664 return rdbSaveType(rdb,REDIS_RDB_TYPE_STRING);665666 case REDIS_LIST:667 if (o-encoding REDIS_ENCODING_ZIPLIST)668 return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST_ZIPLIST);669 else if (o-encoding REDIS_ENCODING_LINKEDLIST)670 return rdbSaveType(rdb,REDIS_RDB_TYPE_LIST);671 else672 redisPanic(Unknown list encoding);673674 case REDIS_SET:675 if (o-encoding REDIS_ENCODING_INTSET)676 return rdbSaveType(rdb,REDIS_RDB_TYPE_SET_INTSET);677 else if (o-encoding REDIS_ENCODING_HT)678 return rdbSaveType(rdb,REDIS_RDB_TYPE_SET);679 else680 redisPanic(Unknown set encoding);681682 case REDIS_ZSET:683 if (o-encoding REDIS_ENCODING_ZIPLIST)684 return rdbSaveType(rdb,REDIS_RDB_TYPE_ZSET_ZIPLIST);685 else if (o-encoding REDIS_ENCODING_SKIPLIST)686 return rdbSaveType(rdb,REDIS_RDB_TYPE_ZSET);687 else688 redisPanic(Unknown sorted set encoding);689690 case REDIS_HASH:691 if (o-encoding REDIS_ENCODING_ZIPLIST)692 return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH_ZIPLIST);693 else if (o-encoding REDIS_ENCODING_HT)694 return rdbSaveType(rdb,REDIS_RDB_TYPE_HASH);695 else696 redisPanic(Unknown hash encoding);697698 default:699 redisPanic(Unknown object type);700 }701702 return -1; /* avoid warning */703 }rdbSaveStringObjectRaw 493 /* Like rdbSaveStringObjectRaw() but handle encoded objects */494 /*495 * 将给定的字符串对象 obj 保存到 rdb 中。496 *497 * 函数返回 rdb 保存字符串对象所需的字节数。498 *499 * p.s. 代码原本的注释 rdbSaveStringObjectRaw() 函数已经不存在了。500 */501 int rdbSaveStringObject(rio *rdb, robj *obj) {502503 /* Avoid to decode the object, then encode it again, if the504 * object is already integer encoded. */505 // 尝试对 INT 编码的字符串进行特殊编码506 if (obj-encoding REDIS_ENCODING_INT) {507 return rdbSaveLongLongAsStringObject(rdb,(long)obj-ptr);508509 // 保存 STRING 编码的字符串510 } else {511 redisAssertWithInfo(NULL,obj,sdsEncodedObject(obj));512 return rdbSaveRawString(rdb,obj-ptr,sdslen(obj-ptr));513 }514 }515rdbSaveLongLongAsStringObject 453 /* Save a long long value as either an encoded string or a string.454 *455 * 将输入的 long long 类型的 value 转换成一个特殊编码的字符串456 * 或者是一个普通的字符串表示的整数457 * 然后将它写入到 rdb 中。458 *459 * 函数返回在 rdb 中保存 value 所需的字节数。460 */461 int rdbSaveLongLongAsStringObject(rio *rdb, long long value) {462 unsigned char buf[32];463 int n, nwritten 0;464465 // 尝试以节省空间的方式编码整数值 value466 int enclen rdbEncodeInteger(value,buf);467468 // 编码成功直接写入编码后的缓存469 // 比如值 1 可以编码为 11 00 0001470 if (enclen 0) {471 return rdbWriteRaw(rdb,buf,enclen);472473 // 编码失败将整数值转换成对应的字符串来保存474 // 比如值 999999999 要编码成 999999999 475 // 因为这个值没办法用节省空间的方式编码476 } else {477 /* Encode as string */478 // 转换成字符串表示479 enclen ll2string((char*)buf,32,value);480 redisAssert(enclen 32);481 // 写入字符串长度482 if ((n rdbSaveLen(rdb,enclen)) -1) return -1;483 nwritten n;484 // 写入字符串485 if ((n rdbWriteRaw(rdb,buf,enclen)) -1) return -1;486 nwritten n;487 }488489 // 返回长度490 return nwritten;491 }492