5️⃣ Recovery / Startup 内部实现
1. 函数集合
1 2 3
| static int kvstore_replay_log(); static int kvstore_load_snapshot(); static int kvstore_log_header();
|
2. 函数复盘 + 规范注释
2.1 static int kvstore_replay_log()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
static int kvstore_replay_log(kvstore* store) { if (!store || !store->tree || !store->log_fp) RETURN_ERR(KVSTORE_ERR_NULL);
if (store->state != KVSTORE_STATE_RECOVERING) { RETURN_ERR(KVSTORE_ERR_INTERNAL); }
char line[256]; int rc = KVSTORE_OK; replay_stats stats = {0};
rewind(store->log_fp);
if (!fgets(line, sizeof(line), store->log_fp)) { goto out; }
if (kvstore_log_header(line) != KVSTORE_OK) { stats.corrupted++; rc = KVSTORE_ERR_WAL_CORRUPTED; goto out; }
while (fgets(line, sizeof(line), store->log_fp)) { if (line[0] == '\n' || line[0] == '\r' || line[0] == ' ') continue; line[strcspn(line, "\r\n")] = '\0';
char* sep = strchr(line, '|'); if (!sep) { stats.skipped++; rc = KVSTORE_OK; break; }
*sep = '\0'; char* crc_str = sep + 1;
if (!kvstore_crc_check(line, crc_str)) { stats.corrupted++;
if (feof(store->log_fp)) { rc = KVSTORE_OK; } else { rc = KVSTORE_ERR_WAL_CORRUPTED; fprintf(stderr, "[REPLAY] 中间数据损坏! Payload: [%s]\n", line); } break; }
int key; long val; int ret;
if (sscanf(line, "PUT %d %ld", &key, &val) == 2) { ret = kvstore_replay_put(store, key, val); } else if (sscanf(line, "DEL %d", &key) == 1) { ret = kvstore_replay_del(store, key); } else { stats.skipped++; continue;
}
if (ret == KVSTORE_OK) { stats.applied++; } else { rc = ret; break; } } int total = stats.applied + stats.skipped + stats.corrupted;
out:
printf( "[RECOVERY] applied=%d skipped=%d corrupted=%d success_rate=%.2f%%\n", stats.applied, stats.skipped, stats.corrupted, total ? (100.0 * stats.applied / total) : 100.0);
if (rc != KVSTORE_OK) { return kvstore_fatal(store, rc); }
return KVSTORE_OK; }
|
2.2 static int kvstore_load_snapshot()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
static int kvstore_load_snapshot(kvstore* store) { if (!store) return KVSTORE_ERR_NULL;
FILE* fp = fopen("data.snapshot", "r"); if (!fp) { return KVSTORE_OK; }
char line[256]; int key; long value;
while (fgets(line, sizeof(line), fp)) { if (line[0] == '\n' || line[0] == '\r') continue;
if (sscanf(line, "PUT %d %ld", &key, &value) == 2) { kvstore_apply_put_internal(store->tree, key, value); }
}
fclose(fp); return KVSTORE_OK; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
static int kvstore_log_header(const char* line) { if (strncmp(line, KVSTORE_LOG_VERSION, strlen(KVSTORE_LOG_VERSION)) != 0) { fprintf(stderr, "Invalid log version. Expected: %s\n", KVSTORE_LOG_VERSION); return KVSTORE_ERR_WAL_CORRUPTED; }
return KVSTORE_OK; }
|