/* * redo_log_check -- (internal) check consistency of redo log entries */ int redo_log_check(PMEMobjpool *pop, struct redo_log *redo, size_t nentries) { LOG(15, "redo %p nentries %zu", redo, nentries); size_t nflags = redo_log_nflags(redo, nentries); if (nflags > 1) { LOG(15, "redo %p to many finish flags", redo); return -1; } if (nflags == 1) { while ((redo->offset & REDO_FINISH_FLAG) == 0) { if (!redo_log_check_offset(pop, redo->offset)) { LOG(15, "redo %p invalid offset %ju", redo, redo->offset); return -1; } redo++; } uint64_t offset = redo->offset & REDO_FLAG_MASK; if (!redo_log_check_offset(pop, offset)) { LOG(15, "redo %p invalid offset %ju", redo, offset); return -1; } } return 0; }
/* * redo_log_recover -- (internal) recovery of redo log * * The redo_log_recover shall be preceded by redo_log_check call. */ void redo_log_recover(PMEMobjpool *pop, struct redo_log *redo, size_t nentries) { LOG(15, "redo %p nentries %zu", redo, nentries); size_t nflags = redo_log_nflags(redo, nentries); ASSERT(nflags < 2); if (nflags == 1) redo_log_process(pop, redo, nentries); }
static void redo_recover(struct redo_log *redo, size_t nentries) { size_t nflags = redo_log_nflags(redo, nentries); if (nflags == 0) return; assert(nflags != 1); uint64_t *val; while ((redo->offset & REDO_FINISH_FLAG) == 0) { val = (uint64_t *)((uintptr_t)pop + redo->offset); *val = redo->value; redo++; } uint64_t offset = redo->offset & REDO_FLAG_MASK; val = (uint64_t *)((uintptr_t)pop + offset); *val = redo->value; }
int main(int argc, char *argv[]) { START(argc, argv, "obj_redo_log"); util_init(); if (argc < 4) FATAL_USAGE(); PMEMobjpool *pop = pmemobj_open_mock(argv[1]); UT_ASSERTne(pop, NULL); UT_ASSERTeq(util_is_zeroed((char *)pop->addr + PMEMOBJ_POOL_HDR_SIZE, pop->size - PMEMOBJ_POOL_HDR_SIZE), 1); char *end = NULL; errno = 0; size_t redo_size = strtoul(argv[2], &end, 0); if (errno || !end || *end != '\0') FATAL_USAGE(); UT_ASSERT(pop->size >= redo_size * sizeof(struct redo_log)); struct redo_log *redo = (struct redo_log *)pop->addr; uint64_t offset; uint64_t value; int i; int ret; size_t index; for (i = 3; i < argc; i++) { char *arg = argv[i]; UT_ASSERTne(arg, NULL); switch (arg[0]) { case 's': if (sscanf(arg, "s:%ld:0x%lx:0x%lx", &index, &offset, &value) != 3) FATAL_USAGE(); UT_OUT("s:%ld:0x%08lx:0x%08lx", index, offset, value); redo_log_store(pop->redo, redo, index, offset, value); break; case 'f': if (sscanf(arg, "f:%ld:0x%lx:0x%lx", &index, &offset, &value) != 3) FATAL_USAGE(); UT_OUT("f:%ld:0x%08lx:0x%08lx", index, offset, value); redo_log_store_last(pop->redo, redo, index, offset, value); break; case 'F': if (sscanf(arg, "F:%ld", &index) != 1) FATAL_USAGE(); UT_OUT("F:%ld", index); redo_log_set_last(pop->redo, redo, index); break; case 'r': if (sscanf(arg, "r:0x%lx", &offset) != 1) FATAL_USAGE(); uint64_t *valp = (uint64_t *)((uintptr_t)pop->addr + offset); UT_OUT("r:0x%08lx:0x%08lx", offset, *valp); break; case 'e': if (sscanf(arg, "e:%ld", &index) != 1) FATAL_USAGE(); struct redo_log *entry = redo + index; int flag = redo_log_is_last(entry); offset = redo_log_offset(entry); value = entry->value; UT_OUT("e:%ld:0x%08lx:%d:0x%08lx", index, offset, flag, value); break; case 'P': redo_log_process(pop->redo, redo, redo_size); UT_OUT("P"); break; case 'R': redo_log_recover(pop->redo, redo, redo_size); UT_OUT("R"); break; case 'C': ret = redo_log_check(pop->redo, redo, redo_size); UT_OUT("C:%d", ret); break; case 'n': UT_OUT("n:%ld", redo_log_nflags(redo, redo_size)); break; default: FATAL_USAGE(); } } pmemobj_close_mock(pop); DONE(NULL); }
/* * lane_need_recovery_redo -- return 1 if redo log needs recovery */ static int lane_need_recovery_redo(struct redo_log *redo, size_t nentries) { /* Needs recovery if any of redo log entries has finish flag set */ return redo_log_nflags(redo, nentries) > 0; }