关键词搜索

源码搜索 ×
×

漫话Redis源码之二十九

发布2021-12-12浏览553次

详情内容

这里主要讲rdb的一些check信息,不是咱们缕清逻辑的重点,不想看的话,可以跳过:

  1. struct {
  2. rio *rio;
  3. robj *key; /* Current key we are reading. */
  4. int key_type; /* Current key type if != -1. */
  5. unsigned long keys; /* Number of keys processed. */
  6. unsigned long expires; /* Number of keys with an expire. */
  7. unsigned long already_expired; /* Number of keys already expired. */
  8. int doing; /* The state while reading the RDB. */
  9. int error_set; /* True if error is populated. */
  10. char error[1024];
  11. } rdbstate;
  12. /* At every loading step try to remember what we were about to do, so that
  13. * we can log this information when an error is encountered. */
  14. #define RDB_CHECK_DOING_START 0
  15. #define RDB_CHECK_DOING_READ_TYPE 1
  16. #define RDB_CHECK_DOING_READ_EXPIRE 2
  17. #define RDB_CHECK_DOING_READ_KEY 3
  18. #define RDB_CHECK_DOING_READ_OBJECT_VALUE 4
  19. #define RDB_CHECK_DOING_CHECK_SUM 5
  20. #define RDB_CHECK_DOING_READ_LEN 6
  21. #define RDB_CHECK_DOING_READ_AUX 7
  22. #define RDB_CHECK_DOING_READ_MODULE_AUX 8
  23. char *rdb_check_doing_string[] = {
  24. "start",
  25. "read-type",
  26. "read-expire",
  27. "read-key",
  28. "read-object-value",
  29. "check-sum",
  30. "read-len",
  31. "read-aux",
  32. "read-module-aux"
  33. };
  34. char *rdb_type_string[] = {
  35. "string",
  36. "list-linked",
  37. "set-hashtable",
  38. "zset-v1",
  39. "hash-hashtable",
  40. "zset-v2",
  41. "module-value",
  42. "","",
  43. "hash-zipmap",
  44. "list-ziplist",
  45. "set-intset",
  46. "zset-ziplist",
  47. "hash-ziplist",
  48. "quicklist",
  49. "stream"
  50. };
  51. /* Show a few stats collected into 'rdbstate' */
  52. void rdbShowGenericInfo(void) {
  53. printf("[info] %lu keys read\n", rdbstate.keys);
  54. printf("[info] %lu expires\n", rdbstate.expires);
  55. printf("[info] %lu already expired\n", rdbstate.already_expired);
  56. }
  57. /* Called on RDB errors. Provides details about the RDB and the offset
  58. * we were when the error was detected. */
  59. void rdbCheckError(const char *fmt, ...) {
  60. char msg[1024];
  61. va_list ap;
  62. va_start(ap, fmt);
  63. vsnprintf(msg, sizeof(msg), fmt, ap);
  64. va_end(ap);
  65. printf("--- RDB ERROR DETECTED ---\n");
  66. printf("[offset %llu] %s\n",
  67. (unsigned long long) (rdbstate.rio ?
  68. rdbstate.rio->processed_bytes : 0), msg);
  69. printf("[additional info] While doing: %s\n",
  70. rdb_check_doing_string[rdbstate.doing]);
  71. if (rdbstate.key)
  72. printf("[additional info] Reading key '%s'\n",
  73. (char*)rdbstate.key->ptr);
  74. if (rdbstate.key_type != -1)
  75. printf("[additional info] Reading type %d (%s)\n",
  76. rdbstate.key_type,
  77. ((unsigned)rdbstate.key_type <
  78. sizeof(rdb_type_string)/sizeof(char*)) ?
  79. rdb_type_string[rdbstate.key_type] : "unknown");
  80. rdbShowGenericInfo();
  81. }
  82. /* Print informations during RDB checking. */
  83. void rdbCheckInfo(const char *fmt, ...) {
  84. char msg[1024];
  85. va_list ap;
  86. va_start(ap, fmt);
  87. vsnprintf(msg, sizeof(msg), fmt, ap);
  88. va_end(ap);
  89. printf("[offset %llu] %s\n",
  90. (unsigned long long) (rdbstate.rio ?
  91. rdbstate.rio->processed_bytes : 0), msg);
  92. }
  93. /* Used inside rdb.c in order to log specific errors happening inside
  94. * the RDB loading internals. */
  95. void rdbCheckSetError(const char *fmt, ...) {
  96. va_list ap;
  97. va_start(ap, fmt);
  98. vsnprintf(rdbstate.error, sizeof(rdbstate.error), fmt, ap);
  99. va_end(ap);
  100. rdbstate.error_set = 1;
  101. }
  102. /* During RDB check we setup a special signal handler for memory violations
  103. * and similar conditions, so that we can log the offending part of the RDB
  104. * if the crash is due to broken content. */
  105. void rdbCheckHandleCrash(int sig, siginfo_t *info, void *secret) {
  106. UNUSED(sig);
  107. UNUSED(info);
  108. UNUSED(secret);
  109. rdbCheckError("Server crash checking the specified RDB file!");
  110. exit(1);
  111. }
  112. void rdbCheckSetupSignals(void) {
  113. struct sigaction act;
  114. sigemptyset(&act.sa_mask);
  115. act.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
  116. act.sa_sigaction = rdbCheckHandleCrash;
  117. sigaction(SIGSEGV, &act, NULL);
  118. sigaction(SIGBUS, &act, NULL);
  119. sigaction(SIGFPE, &act, NULL);
  120. sigaction(SIGILL, &act, NULL);
  121. sigaction(SIGABRT, &act, NULL);
  122. }
  123. /* Check the specified RDB file. Return 0 if the RDB looks sane, otherwise
  124. * 1 is returned.
  125. * The file is specified as a filename in 'rdbfilename' if 'fp' is not NULL,
  126. * otherwise the already open file 'fp' is checked. */
  127. int redis_check_rdb(char *rdbfilename, FILE *fp) {
  128. uint64_t dbid;
  129. int type, rdbver;
  130. char buf[1024];
  131. long long expiretime, now = mstime();
  132. static rio rdb; /* Pointed by global struct riostate. */
  133. int closefile = (fp == NULL);
  134. if (fp == NULL && (fp = fopen(rdbfilename,"r")) == NULL) return 1;
  135. startLoadingFile(fp, rdbfilename, RDBFLAGS_NONE);
  136. rioInitWithFile(&rdb,fp);
  137. rdbstate.rio = &rdb;
  138. rdb.update_cksum = rdbLoadProgressCallback;
  139. if (rioRead(&rdb,buf,9) == 0) goto eoferr;
  140. buf[9] = '\0';
  141. if (memcmp(buf,"REDIS",5) != 0) {
  142. rdbCheckError("Wrong signature trying to load DB from file");
  143. goto err;
  144. }
  145. rdbver = atoi(buf+5);
  146. if (rdbver < 1 || rdbver > RDB_VERSION) {
  147. rdbCheckError("Can't handle RDB format version %d",rdbver);
  148. goto err;
  149. }
  150. expiretime = -1;
  151. while(1) {
  152. robj *key, *val;
  153. /* Read type. */
  154. rdbstate.doing = RDB_CHECK_DOING_READ_TYPE;
  155. if ((type = rdbLoadType(&rdb)) == -1) goto eoferr;
  156. /* Handle special types. */
  157. if (type == RDB_OPCODE_EXPIRETIME) {
  158. rdbstate.doing = RDB_CHECK_DOING_READ_EXPIRE;
  159. /* EXPIRETIME: load an expire associated with the next key
  160. * to load. Note that after loading an expire we need to
  161. * load the actual type, and continue. */
  162. expiretime = rdbLoadTime(&rdb);
  163. expiretime *= 1000;
  164. if (rioGetReadError(&rdb)) goto eoferr;
  165. continue; /* Read next opcode. */
  166. } else if (type == RDB_OPCODE_EXPIRETIME_MS) {
  167. /* EXPIRETIME_MS: milliseconds precision expire times introduced
  168. * with RDB v3. Like EXPIRETIME but no with more precision. */
  169. rdbstate.doing = RDB_CHECK_DOING_READ_EXPIRE;
  170. expiretime = rdbLoadMillisecondTime(&rdb, rdbver);
  171. if (rioGetReadError(&rdb)) goto eoferr;
  172. continue; /* Read next opcode. */
  173. } else if (type == RDB_OPCODE_FREQ) {
  174. /* FREQ: LFU frequency. */
  175. uint8_t byte;
  176. if (rioRead(&rdb,&byte,1) == 0) goto eoferr;
  177. continue; /* Read next opcode. */
  178. } else if (type == RDB_OPCODE_IDLE) {
  179. /* IDLE: LRU idle time. */
  180. if (rdbLoadLen(&rdb,NULL) == RDB_LENERR) goto eoferr;
  181. continue; /* Read next opcode. */
  182. } else if (type == RDB_OPCODE_EOF) {
  183. /* EOF: End of file, exit the main loop. */
  184. break;
  185. } else if (type == RDB_OPCODE_SELECTDB) {
  186. /* SELECTDB: Select the specified database. */
  187. rdbstate.doing = RDB_CHECK_DOING_READ_LEN;
  188. if ((dbid = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
  189. goto eoferr;
  190. rdbCheckInfo("Selecting DB ID %llu", (unsigned long long)dbid);
  191. continue; /* Read type again. */
  192. } else if (type == RDB_OPCODE_RESIZEDB) {
  193. /* RESIZEDB: Hint about the size of the keys in the currently
  194. * selected data base, in order to avoid useless rehashing. */
  195. uint64_t db_size, expires_size;
  196. rdbstate.doing = RDB_CHECK_DOING_READ_LEN;
  197. if ((db_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
  198. goto eoferr;
  199. if ((expires_size = rdbLoadLen(&rdb,NULL)) == RDB_LENERR)
  200. goto eoferr;
  201. continue; /* Read type again. */
  202. } else if (type == RDB_OPCODE_AUX) {
  203. /* AUX: generic string-string fields. Use to add state to RDB
  204. * which is backward compatible. Implementations of RDB loading
  205. * are requierd to skip AUX fields they don't understand.
  206. *
  207. * An AUX field is composed of two strings: key and value. */
  208. robj *auxkey, *auxval;
  209. rdbstate.doing = RDB_CHECK_DOING_READ_AUX;
  210. if ((auxkey = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
  211. if ((auxval = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
  212. rdbCheckInfo("AUX FIELD %s = '%s'",
  213. (char*)auxkey->ptr, (char*)auxval->ptr);
  214. decrRefCount(auxkey);
  215. decrRefCount(auxval);
  216. continue; /* Read type again. */
  217. } else if (type == RDB_OPCODE_MODULE_AUX) {
  218. /* AUX: Auxiliary data for modules. */
  219. uint64_t moduleid, when_opcode, when;
  220. rdbstate.doing = RDB_CHECK_DOING_READ_MODULE_AUX;
  221. if ((moduleid = rdbLoadLen(&rdb,NULL)) == RDB_LENERR) goto eoferr;
  222. if ((when_opcode = rdbLoadLen(&rdb,NULL)) == RDB_LENERR) goto eoferr;
  223. if ((when = rdbLoadLen(&rdb,NULL)) == RDB_LENERR) goto eoferr;
  224. char name[10];
  225. moduleTypeNameByID(name,moduleid);
  226. rdbCheckInfo("MODULE AUX for: %s", name);
  227. robj *o = rdbLoadCheckModuleValue(&rdb,name);
  228. decrRefCount(o);
  229. continue; /* Read type again. */
  230. } else {
  231. if (!rdbIsObjectType(type)) {
  232. rdbCheckError("Invalid object type: %d", type);
  233. goto err;
  234. }
  235. rdbstate.key_type = type;
  236. }
  237. /* Read key */
  238. rdbstate.doing = RDB_CHECK_DOING_READ_KEY;
  239. if ((key = rdbLoadStringObject(&rdb)) == NULL) goto eoferr;
  240. rdbstate.key = key;
  241. rdbstate.keys++;
  242. /* Read value */
  243. rdbstate.doing = RDB_CHECK_DOING_READ_OBJECT_VALUE;
  244. if ((val = rdbLoadObject(type,&rdb,key->ptr,NULL)) == NULL) goto eoferr;
  245. /* Check if the key already expired. */
  246. if (expiretime != -1 && expiretime < now)
  247. rdbstate.already_expired++;
  248. if (expiretime != -1) rdbstate.expires++;
  249. rdbstate.key = NULL;
  250. decrRefCount(key);
  251. decrRefCount(val);
  252. rdbstate.key_type = -1;
  253. expiretime = -1;
  254. }
  255. /* Verify the checksum if RDB version is >= 5 */
  256. if (rdbver >= 5 && server.rdb_checksum) {
  257. uint64_t cksum, expected = rdb.cksum;
  258. rdbstate.doing = RDB_CHECK_DOING_CHECK_SUM;
  259. if (rioRead(&rdb,&cksum,8) == 0) goto eoferr;
  260. memrev64ifbe(&cksum);
  261. if (cksum == 0) {
  262. rdbCheckInfo("RDB file was saved with checksum disabled: no check performed.");
  263. } else if (cksum != expected) {
  264. rdbCheckError("RDB CRC error");
  265. goto err;
  266. } else {
  267. rdbCheckInfo("Checksum OK");
  268. }
  269. }
  270. if (closefile) fclose(fp);
  271. stopLoading(1);
  272. return 0;
  273. eoferr: /* unexpected end of file is handled here with a fatal exit */
  274. if (rdbstate.error_set) {
  275. rdbCheckError(rdbstate.error);
  276. } else {
  277. rdbCheckError("Unexpected EOF reading RDB file");
  278. }
  279. err:
  280. if (closefile) fclose(fp);
  281. stopLoading(0);
  282. return 1;
  283. }

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载