/* * __txn_log_recover -- * Roll the log forward to recover committed changes. */ static int __txn_log_recover(WT_SESSION_IMPL *session, WT_ITEM *logrec, WT_LSN *lsnp, WT_LSN *next_lsnp, void *cookie, int firstrecord) { WT_RECOVERY *r; const uint8_t *end, *p; uint64_t txnid; uint32_t rectype; WT_UNUSED(next_lsnp); r = cookie; p = WT_LOG_SKIP_HEADER(logrec->data); end = (const uint8_t *)logrec->data + logrec->size; WT_UNUSED(firstrecord); /* First, peek at the log record type. */ WT_RET(__wt_logrec_read(session, &p, end, &rectype)); switch (rectype) { case WT_LOGREC_CHECKPOINT: if (r->metadata_only) WT_RET(__wt_txn_checkpoint_logread( session, &p, end, &r->ckpt_lsn)); break; case WT_LOGREC_COMMIT: WT_RET(__wt_vunpack_uint(&p, WT_PTRDIFF(end, p), &txnid)); WT_UNUSED(txnid); WT_RET(__txn_commit_apply(r, lsnp, &p, end)); break; } return (0); }
/* * __txn_log_recover -- * Roll the log forward to recover committed changes. */ static int __txn_log_recover(WT_SESSION_IMPL *session, WT_ITEM *logrec, WT_LSN *lsnp, WT_LSN *next_lsnp, void *cookie, int firstrecord) { WT_DECL_RET; WT_RECOVERY *r; uint64_t txnid_unused; uint32_t rectype; const uint8_t *end, *p; r = cookie; p = WT_LOG_SKIP_HEADER(logrec->data); end = (const uint8_t *)logrec->data + logrec->size; WT_UNUSED(firstrecord); /* First, peek at the log record type. */ WT_RET(__wt_logrec_read(session, &p, end, &rectype)); /* * Record the highest LSN we process during the metadata phase. * If not the metadata phase, then stop at that LSN. */ if (r->metadata_only) r->max_rec_lsn = *next_lsnp; else if (__wt_log_cmp(lsnp, &r->max_rec_lsn) >= 0) return (0); switch (rectype) { case WT_LOGREC_CHECKPOINT: if (r->metadata_only) WT_RET(__wt_txn_checkpoint_logread( session, &p, end, &r->ckpt_lsn)); break; case WT_LOGREC_COMMIT: if ((ret = __wt_vunpack_uint( &p, WT_PTRDIFF(end, p), &txnid_unused)) != 0) WT_RET_MSG( session, ret, "txn_log_recover: unpack failure"); WT_RET(__txn_commit_apply(r, lsnp, &p, end)); break; } return (0); }
/* * __curlog_logrec -- * Callback function from log_scan to get a log record. */ static int __curlog_logrec(WT_SESSION_IMPL *session, WT_ITEM *logrec, WT_LSN *lsnp, WT_LSN *next_lsnp, void *cookie, int firstrecord) { WT_CURSOR_LOG *cl; cl = cookie; WT_UNUSED(firstrecord); /* Set up the LSNs and take a copy of the log record for the cursor. */ *cl->cur_lsn = *lsnp; *cl->next_lsn = *next_lsnp; WT_RET(__wt_buf_set(session, cl->logrec, logrec->data, logrec->size)); /* * Read the log header. Set up the step pointers to walk the * operations inside the record. Get the record type. */ cl->stepp = WT_LOG_SKIP_HEADER(cl->logrec->data); cl->stepp_end = (uint8_t *)cl->logrec->data + logrec->size; WT_RET(__wt_logrec_read(session, &cl->stepp, cl->stepp_end, &cl->rectype)); /* A step count of 0 means the entire record. */ cl->step_count = 0; /* * Unpack the txnid so that we can return each * individual operation for this txnid. */ if (cl->rectype == WT_LOGREC_COMMIT) WT_RET(__wt_vunpack_uint(&cl->stepp, WT_PTRDIFF(cl->stepp_end, cl->stepp), &cl->txnid)); else { /* * Step over anything else. * Setting stepp to NULL causes the next() * method to read a new record on the next call. */ cl->stepp = NULL; cl->txnid = 0; } return (0); }
/* * __txn_printlog -- * Print a log record in a human-readable format. */ static int __txn_printlog( WT_SESSION_IMPL *session, WT_ITEM *logrec, WT_LSN *lsnp, void *cookie) { FILE *out; WT_LSN ckpt_lsn; const uint8_t *end, *p; const char *msg; uint64_t txnid; uint32_t fileid, rectype; int32_t start; out = cookie; p = (const uint8_t *)logrec->data + offsetof(WT_LOG_RECORD, record); end = (const uint8_t *)logrec->data + logrec->size; /* First, peek at the log record type. */ WT_RET(__wt_logrec_read(session, &p, end, &rectype)); if (fprintf(out, " { \"lsn\" : [%" PRIu32 ",%" PRId64 "],\n", lsnp->file, lsnp->offset) < 0) return (errno); switch (rectype) { case WT_LOGREC_CHECKPOINT: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(IQ), &ckpt_lsn.file, &ckpt_lsn.offset)); if (fprintf(out, " \"type\" : \"checkpoint\"\n") < 0 || fprintf( out, " \"ckpt_lsn\" : [%" PRIu32 ",%" PRId64 "],\n", ckpt_lsn.file, ckpt_lsn.offset) < 0) return (errno); break; case WT_LOGREC_COMMIT: WT_RET(__wt_vunpack_uint(&p, WT_PTRDIFF(end, p), &txnid)); if (fprintf(out, " \"type\" : \"commit\"\n") < 0 || fprintf(out, " \"txnid\" : %" PRIu64 ",\n", txnid) < 0) return (errno); WT_RET(__txn_commit_printlog(session, &p, end, out)); break; case WT_LOGREC_FILE_SYNC: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(Ii), &fileid, &start)); if (fprintf(out, " \"type\" : \"file_sync\"\n") < 0 || fprintf(out, " \"fileid\" : %" PRIu32 "\n", fileid) < 0 || fprintf(out, " \"start\" : %" PRId32 "\n", start) < 0) return (errno); break; case WT_LOGREC_MESSAGE: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(S), &msg)); if (fprintf(out, " \"type\" : \"message\"\n") < 0 || fprintf(out, " \"message\" : \"%s\"\n", msg) < 0) return (errno); break; } if (fprintf(out, " },\n") < 0) return (errno); return (0); }
/* * __txn_printlog -- * Print a log record in a human-readable format. */ static int __txn_printlog(WT_SESSION_IMPL *session, WT_ITEM *rawrec, WT_LSN *lsnp, WT_LSN *next_lsnp, void *cookie, int firstrecord) { WT_LOG_RECORD *logrec; WT_TXN_PRINTLOG_ARGS *args; const uint8_t *end, *p; const char *msg; uint64_t txnid; uint32_t fileid, lsnfile, lsnoffset, rectype; int32_t start; bool compressed; WT_UNUSED(next_lsnp); args = cookie; p = WT_LOG_SKIP_HEADER(rawrec->data); end = (const uint8_t *)rawrec->data + rawrec->size; logrec = (WT_LOG_RECORD *)rawrec->data; compressed = F_ISSET(logrec, WT_LOG_RECORD_COMPRESSED); /* First, peek at the log record type. */ WT_RET(__wt_logrec_read(session, &p, end, &rectype)); if (!firstrecord) WT_RET(__wt_fprintf(session, WT_STDOUT(session), ",\n")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " { \"lsn\" : [%" PRIu32 ",%" PRIu32 "],\n", lsnp->l.file, lsnp->l.offset)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"hdr_flags\" : \"%s\",\n", compressed ? "compressed" : "")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"rec_len\" : %" PRIu32 ",\n", logrec->len)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"mem_len\" : %" PRIu32 ",\n", compressed ? logrec->mem_len : logrec->len)); switch (rectype) { case WT_LOGREC_CHECKPOINT: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(II), &lsnfile, &lsnoffset)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"type\" : \"checkpoint\",\n")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"ckpt_lsn\" : [%" PRIu32 ",%" PRIu32 "]\n", lsnfile, lsnoffset)); break; case WT_LOGREC_COMMIT: WT_RET(__wt_vunpack_uint(&p, WT_PTRDIFF(end, p), &txnid)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"type\" : \"commit\",\n")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"txnid\" : %" PRIu64 ",\n", txnid)); WT_RET(__txn_oplist_printlog(session, &p, end, args->flags)); break; case WT_LOGREC_FILE_SYNC: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(Ii), &fileid, &start)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"type\" : \"file_sync\",\n")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"fileid\" : %" PRIu32 ",\n", fileid)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"start\" : %" PRId32 "\n", start)); break; case WT_LOGREC_MESSAGE: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(S), &msg)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"type\" : \"message\",\n")); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"message\" : \"%s\"\n", msg)); break; case WT_LOGREC_SYSTEM: WT_RET(__wt_struct_unpack(session, p, WT_PTRDIFF(end, p), WT_UNCHECKED_STRING(II), &lsnfile, &lsnoffset)); WT_RET(__wt_fprintf(session, WT_STDOUT(session), " \"type\" : \"system\",\n")); WT_RET(__txn_oplist_printlog(session, &p, end, args->flags)); break; } WT_RET(__wt_fprintf(session, WT_STDOUT(session), " }")); return (0); }