redis源码剖析(十二)—— RDB持久化
生活随笔
收集整理的這篇文章主要介紹了
redis源码剖析(十二)—— RDB持久化
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- RBD文件載入
- RDB文件分析
- 源碼分析
- 核心代碼
- rdb文件寫入
- rdb寫入關鍵函數rdbSaveObjectType
- rdbSaveStringObjectRaw
- rdbSaveLongLongAsStringObject
為避免數據丟失。將redis中的數據保存到磁盤中,避免數據意外丟失。
RBD文件載入
在redis啟動時檢測是否有rdb文件,有的話會自動載入。
| save | 阻塞服務器進程,知道rbd文件創建完成 |
| bgsave | fork子進程,由子進程負責創建RDB文件 |
RDB文件分析
[root@python 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 [root@python 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 [root@python 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 $ 0000155-
0000000 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 。
核心代碼
// 遍歷所有數據庫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);}- 獲取鍵值和鍵
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總結
以上是生活随笔為你收集整理的redis源码剖析(十二)—— RDB持久化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ^M
- 下一篇: redis源码剖析(十三)—— dump