/* * __curlog_kv -- * Set the key and value of the log cursor to return to the user. */ static int __curlog_kv(WT_SESSION_IMPL *session, WT_CURSOR *cursor) { WT_CURSOR_LOG *cl; WT_DECL_RET; uint32_t fileid, key_count, opsize, optype, raw; cl = (WT_CURSOR_LOG *)cursor; /* Temporarily turn off raw so we can do direct cursor operations. */ raw = F_MASK(cursor, WT_CURSTD_RAW); F_CLR(cursor, WT_CURSTD_RAW); /* * If it is a commit and we have stepped over the header, peek to get * the size and optype and read out any key/value from this operation. */ if ((key_count = cl->step_count++) > 0) { WT_ERR(__wt_logop_read(session, &cl->stepp, cl->stepp_end, &optype, &opsize)); WT_ERR(__curlog_op_read(session, cl, optype, opsize, &fileid)); /* Position on the beginning of the next record part. */ cl->stepp += opsize; } else { optype = WT_LOGOP_INVALID; fileid = 0; cl->opkey->data = NULL; cl->opkey->size = 0; /* * Non-commit records we want to return the record without the * header and the adjusted size. Add one to skip over the type * which is normally consumed by __wt_logrec_read. */ cl->opvalue->data = WT_LOG_SKIP_HEADER(cl->logrec->data) + 1; cl->opvalue->size = WT_LOG_REC_SIZE(cl->logrec->size) - 1; } /* * The log cursor sets the LSN and step count as the cursor key and * and log record related data in the value. The data in the value * contains any operation key/value that was in the log record. */ __wt_cursor_set_key(cursor, cl->cur_lsn->l.file, cl->cur_lsn->l.offset, key_count); __wt_cursor_set_value(cursor, cl->txnid, cl->rectype, optype, fileid, cl->opkey, cl->opvalue); err: F_SET(cursor, raw); return (ret); }
int __wt_txn_op_printlog( WT_SESSION_IMPL *session, const uint8_t **pp, const uint8_t *end, FILE *out) { uint32_t optype, opsize; /* Peek at the size and the type. */ WT_RET(__wt_logop_read(session, pp, end, &optype, &opsize)); end = *pp + opsize; switch (optype) { case WT_LOGOP_COL_PUT: WT_RET(__wt_logop_col_put_print(session, pp, end, out)); break; case WT_LOGOP_COL_REMOVE: WT_RET(__wt_logop_col_remove_print(session, pp, end, out)); break; case WT_LOGOP_COL_TRUNCATE: WT_RET(__wt_logop_col_truncate_print(session, pp, end, out)); break; case WT_LOGOP_ROW_PUT: WT_RET(__wt_logop_row_put_print(session, pp, end, out)); break; case WT_LOGOP_ROW_REMOVE: WT_RET(__wt_logop_row_remove_print(session, pp, end, out)); break; case WT_LOGOP_ROW_TRUNCATE: WT_RET(__wt_logop_row_truncate_print(session, pp, end, out)); break; WT_ILLEGAL_VALUE(session); } return (0); }
/* * __curlog_kv -- * Set the key and value of the log cursor to return to the user. */ static int __curlog_kv(WT_SESSION_IMPL *session, WT_CURSOR *cursor) { WT_CURSOR_LOG *cl; uint32_t fileid, key_count, opsize, optype; cl = (WT_CURSOR_LOG *)cursor; /* * If it is a commit and we have stepped over the header, peek to get * the size and optype and read out any key/value from this operation. */ if ((key_count = cl->step_count++) > 0) { WT_RET(__wt_logop_read(session, &cl->stepp, cl->stepp_end, &optype, &opsize)); WT_RET(__curlog_op_read(session, cl, optype, opsize, &fileid)); /* Position on the beginning of the next record part. */ cl->stepp += opsize; } else { optype = WT_LOGOP_INVALID; fileid = 0; cl->opkey->data = NULL; cl->opkey->size = 0; cl->opvalue->data = cl->logrec->data; cl->opvalue->size = cl->logrec->size; } /* * The log cursor sets the LSN and step count as the cursor key and * and log record related data in the value. The data in the value * contains any operation key/value that was in the log record. */ __wt_cursor_set_key(cursor, cl->cur_lsn->file, cl->cur_lsn->offset, key_count); __wt_cursor_set_value(cursor, cl->txnid, cl->rectype, optype, fileid, cl->opkey, cl->opvalue); return (0); }
/* * __txn_op_apply -- * Apply a transactional operation during recovery. */ static int __txn_op_apply( WT_RECOVERY *r, WT_LSN *lsnp, const uint8_t **pp, const uint8_t *end) { WT_CURSOR *cursor, *start, *stop; WT_DECL_RET; WT_ITEM key, start_key, stop_key, value; WT_SESSION_IMPL *session; uint64_t recno, start_recno, stop_recno; uint32_t fileid, mode, optype, opsize; session = r->session; cursor = NULL; /* Peek at the size and the type. */ WT_ERR(__wt_logop_read(session, pp, end, &optype, &opsize)); end = *pp + opsize; switch (optype) { case WT_LOGOP_COL_PUT: WT_ERR(__wt_logop_col_put_unpack(session, pp, end, &fileid, &recno, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); cursor->set_key(cursor, recno); __wt_cursor_set_raw_value(cursor, &value); WT_ERR(cursor->insert(cursor)); break; case WT_LOGOP_COL_REMOVE: WT_ERR(__wt_logop_col_remove_unpack(session, pp, end, &fileid, &recno)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); cursor->set_key(cursor, recno); WT_ERR(cursor->remove(cursor)); break; case WT_LOGOP_COL_TRUNCATE: WT_ERR(__wt_logop_col_truncate_unpack(session, pp, end, &fileid, &start_recno, &stop_recno)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); /* Set up the cursors. */ if (start_recno == WT_RECNO_OOB) { start = NULL; stop = cursor; } else if (stop_recno == WT_RECNO_OOB) { start = cursor; stop = NULL; } else { start = cursor; WT_ERR(__recovery_cursor( session, r, lsnp, fileid, true, &stop)); } /* Set the keys. */ if (start != NULL) start->set_key(start, start_recno); if (stop != NULL) stop->set_key(stop, stop_recno); WT_TRET(session->iface.truncate(&session->iface, NULL, start, stop, NULL)); /* If we opened a duplicate cursor, close it now. */ if (stop != NULL && stop != cursor) WT_TRET(stop->close(stop)); WT_ERR(ret); break; case WT_LOGOP_ROW_PUT: WT_ERR(__wt_logop_row_put_unpack(session, pp, end, &fileid, &key, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); __wt_cursor_set_raw_key(cursor, &key); __wt_cursor_set_raw_value(cursor, &value); WT_ERR(cursor->insert(cursor)); break; case WT_LOGOP_ROW_REMOVE: WT_ERR(__wt_logop_row_remove_unpack(session, pp, end, &fileid, &key)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); __wt_cursor_set_raw_key(cursor, &key); WT_ERR(cursor->remove(cursor)); break; case WT_LOGOP_ROW_TRUNCATE: WT_ERR(__wt_logop_row_truncate_unpack(session, pp, end, &fileid, &start_key, &stop_key, &mode)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); /* Set up the cursors. */ start = stop = NULL; switch (mode) { case WT_TXN_TRUNC_ALL: /* Both cursors stay NULL. */ break; case WT_TXN_TRUNC_BOTH: start = cursor; WT_ERR(__recovery_cursor( session, r, lsnp, fileid, true, &stop)); break; case WT_TXN_TRUNC_START: start = cursor; break; case WT_TXN_TRUNC_STOP: stop = cursor; break; WT_ILLEGAL_VALUE_ERR(session); } /* Set the keys. */ if (start != NULL) __wt_cursor_set_raw_key(start, &start_key); if (stop != NULL) __wt_cursor_set_raw_key(stop, &stop_key); WT_TRET(session->iface.truncate(&session->iface, NULL, start, stop, NULL)); /* If we opened a duplicate cursor, close it now. */ if (stop != NULL && stop != cursor) WT_TRET(stop->close(stop)); WT_ERR(ret); break; WT_ILLEGAL_VALUE_ERR(session); } /* Reset the cursor so it doesn't block eviction. */ if (cursor != NULL) WT_ERR(cursor->reset(cursor)); err: if (ret != 0) __wt_err(session, ret, "Operation failed during recovery"); return (ret); }
/* * __curlog_kv -- * Set the key and value of the log cursor to return to the user. */ static int __curlog_kv(WT_SESSION_IMPL *session, WT_CURSOR *cursor) { WT_CURSOR_LOG *cl; WT_ITEM item; uint32_t fileid, key_count, opsize, optype; cl = (WT_CURSOR_LOG *)cursor; /* * If it is a commit and we have stepped over the header, peek to get * the size and optype and read out any key/value from this operation. */ if ((key_count = cl->step_count++) > 0) { WT_RET(__wt_logop_read(session, &cl->stepp, cl->stepp_end, &optype, &opsize)); WT_RET(__curlog_op_read(session, cl, optype, opsize, &fileid)); /* Position on the beginning of the next record part. */ cl->stepp += opsize; } else { optype = WT_LOGOP_INVALID; fileid = 0; cl->opkey->data = NULL; cl->opkey->size = 0; /* * Non-commit records we want to return the record without the * header and the adjusted size. Add one to skip over the type * which is normally consumed by __wt_logrec_read. */ cl->opvalue->data = WT_LOG_SKIP_HEADER(cl->logrec->data) + 1; cl->opvalue->size = WT_LOG_REC_SIZE(cl->logrec->size) - 1; } /* * The log cursor sets the LSN and step count as the cursor key and * and log record related data in the value. The data in the value * contains any operation key/value that was in the log record. * For the special case that the caller needs the result in raw form, * we create packed versions of the key/value. */ if (FLD_ISSET(cursor->flags, WT_CURSTD_RAW)) { memset(&item, 0, sizeof(item)); WT_RET(wiredtiger_struct_size((WT_SESSION *)session, &item.size, WT_LOGC_KEY_FORMAT, cl->cur_lsn->l.file, cl->cur_lsn->l.offset, key_count)); WT_RET(__wt_realloc(session, NULL, item.size, &cl->packed_key)); item.data = cl->packed_key; WT_RET(wiredtiger_struct_pack((WT_SESSION *)session, cl->packed_key, item.size, WT_LOGC_KEY_FORMAT, cl->cur_lsn->l.file, cl->cur_lsn->l.offset, key_count)); __wt_cursor_set_key(cursor, &item); WT_RET(wiredtiger_struct_size((WT_SESSION *)session, &item.size, WT_LOGC_VALUE_FORMAT, cl->txnid, cl->rectype, optype, fileid, cl->opkey, cl->opvalue)); WT_RET(__wt_realloc(session, NULL, item.size, &cl->packed_value)); item.data = cl->packed_value; WT_RET(wiredtiger_struct_pack((WT_SESSION *)session, cl->packed_value, item.size, WT_LOGC_VALUE_FORMAT, cl->txnid, cl->rectype, optype, fileid, cl->opkey, cl->opvalue)); __wt_cursor_set_value(cursor, &item); } else { __wt_cursor_set_key(cursor, cl->cur_lsn->l.file, cl->cur_lsn->l.offset, key_count); __wt_cursor_set_value(cursor, cl->txnid, cl->rectype, optype, fileid, cl->opkey, cl->opvalue); } return (0); }
/* * __txn_op_apply -- * Apply a transactional operation during recovery. */ static int __txn_op_apply( WT_RECOVERY *r, WT_LSN *lsnp, const uint8_t **pp, const uint8_t *end) { WT_CURSOR *cursor, *start, *stop; WT_DECL_RET; WT_ITEM key, start_key, stop_key, value; WT_SESSION_IMPL *session; uint64_t recno, start_recno, stop_recno; uint32_t fileid, mode, optype, opsize; session = r->session; cursor = NULL; /* Peek at the size and the type. */ WT_ERR(__wt_logop_read(session, pp, end, &optype, &opsize)); end = *pp + opsize; switch (optype) { case WT_LOGOP_COL_MODIFY: WT_ERR(__wt_logop_col_modify_unpack(session, pp, end, &fileid, &recno, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); cursor->set_key(cursor, recno); if ((ret = cursor->search(cursor)) != 0) WT_ERR_NOTFOUND_OK(ret); else { /* * Build/insert a complete value during recovery rather * than using cursor modify to create a partial update * (for no particular reason than simplicity). */ WT_ERR(__wt_modify_apply(session, cursor, value.data)); WT_ERR(cursor->insert(cursor)); } break; case WT_LOGOP_COL_PUT: WT_ERR(__wt_logop_col_put_unpack(session, pp, end, &fileid, &recno, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); cursor->set_key(cursor, recno); __wt_cursor_set_raw_value(cursor, &value); WT_ERR(cursor->insert(cursor)); break; case WT_LOGOP_COL_REMOVE: WT_ERR(__wt_logop_col_remove_unpack(session, pp, end, &fileid, &recno)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); cursor->set_key(cursor, recno); WT_ERR(cursor->remove(cursor)); break; case WT_LOGOP_COL_TRUNCATE: WT_ERR(__wt_logop_col_truncate_unpack(session, pp, end, &fileid, &start_recno, &stop_recno)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); /* Set up the cursors. */ if (start_recno == WT_RECNO_OOB) { start = NULL; stop = cursor; } else if (stop_recno == WT_RECNO_OOB) { start = cursor; stop = NULL; } else { start = cursor; WT_ERR(__recovery_cursor( session, r, lsnp, fileid, true, &stop)); } /* Set the keys. */ if (start != NULL) start->set_key(start, start_recno); if (stop != NULL) stop->set_key(stop, stop_recno); WT_TRET(session->iface.truncate(&session->iface, NULL, start, stop, NULL)); /* If we opened a duplicate cursor, close it now. */ if (stop != NULL && stop != cursor) WT_TRET(stop->close(stop)); WT_ERR(ret); break; case WT_LOGOP_ROW_MODIFY: WT_ERR(__wt_logop_row_modify_unpack(session, pp, end, &fileid, &key, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); __wt_cursor_set_raw_key(cursor, &key); if ((ret = cursor->search(cursor)) != 0) WT_ERR_NOTFOUND_OK(ret); else { /* * Build/insert a complete value during recovery rather * than using cursor modify to create a partial update * (for no particular reason than simplicity). */ WT_ERR(__wt_modify_apply(session, cursor, value.data)); WT_ERR(cursor->insert(cursor)); } break; case WT_LOGOP_ROW_PUT: WT_ERR(__wt_logop_row_put_unpack(session, pp, end, &fileid, &key, &value)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); __wt_cursor_set_raw_key(cursor, &key); __wt_cursor_set_raw_value(cursor, &value); WT_ERR(cursor->insert(cursor)); break; case WT_LOGOP_ROW_REMOVE: WT_ERR(__wt_logop_row_remove_unpack(session, pp, end, &fileid, &key)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); __wt_cursor_set_raw_key(cursor, &key); WT_ERR(cursor->remove(cursor)); break; case WT_LOGOP_ROW_TRUNCATE: WT_ERR(__wt_logop_row_truncate_unpack(session, pp, end, &fileid, &start_key, &stop_key, &mode)); GET_RECOVERY_CURSOR(session, r, lsnp, fileid, &cursor); /* Set up the cursors. */ start = stop = NULL; switch (mode) { case WT_TXN_TRUNC_ALL: /* Both cursors stay NULL. */ break; case WT_TXN_TRUNC_BOTH: start = cursor; WT_ERR(__recovery_cursor( session, r, lsnp, fileid, true, &stop)); break; case WT_TXN_TRUNC_START: start = cursor; break; case WT_TXN_TRUNC_STOP: stop = cursor; break; WT_ILLEGAL_VALUE_ERR(session, mode); } /* Set the keys. */ if (start != NULL) __wt_cursor_set_raw_key(start, &start_key); if (stop != NULL) __wt_cursor_set_raw_key(stop, &stop_key); WT_TRET(session->iface.truncate(&session->iface, NULL, start, stop, NULL)); /* If we opened a duplicate cursor, close it now. */ if (stop != NULL && stop != cursor) WT_TRET(stop->close(stop)); WT_ERR(ret); break; WT_ILLEGAL_VALUE_ERR(session, optype); } /* Reset the cursor so it doesn't block eviction. */ if (cursor != NULL) WT_ERR(cursor->reset(cursor)); return (0); err: __wt_err(session, ret, "operation apply failed during recovery: operation type %" PRIu32 " at LSN %" PRIu32 "/%" PRIu32, optype, lsnp->l.file, lsnp->l.offset); return (ret); }