// Check whether need to recovery, if yes, reset fseek to the right place. bool WriteBehindFrontendLogger::NeedRecovery(void) { // Otherwise, read the last transaction record fseek(log_file, -TransactionRecord::GetTransactionRecordSize(), SEEK_END); // Get its type auto log_record_type = GetNextLogRecordType(log_file, log_file_size); // Check if the previous transaction run is broken if (log_record_type == LOGRECORD_TYPE_TRANSACTION_COMMIT) { TransactionRecord txn_record(LOGRECORD_TYPE_TRANSACTION_COMMIT); // read the last written out transaction log record if (ReadTransactionRecordHeader(txn_record, log_file, log_file_size) == false) { return false; } // Peloton log records items have fixed size. // Compute log offset based on txn_id size_t tuple_log_record_count = txn_record.GetTransactionId(); size_t rollback_offset = tuple_log_record_count * TupleRecord::GetTupleRecordSize() + TransactionRecord::GetTransactionRecordSize(); // Rollback to the computed offset fseek(log_file, -rollback_offset, SEEK_END); return true; } else { return false; } }
/** * @brief Recovery system based on log file */ void AriesFrontendLogger::DoRecovery() { // Set log file size log_file_size = GetLogFileSize(log_file_fd); // Go over the log size if needed if (log_file_size > 0) { bool reached_end_of_file = false; // Start the recovery transaction auto &txn_manager = concurrency::TransactionManager::GetInstance(); // Although we call BeginTransaction here, recovery txn will not be // recoreded in log file since we are in recovery mode auto recovery_txn = txn_manager.BeginTransaction(); // Go over each log record in the log file while (reached_end_of_file == false) { // Read the first byte to identify log record type // If that is not possible, then wrap up recovery auto record_type = GetNextLogRecordType(log_file, log_file_size); switch (record_type) { case LOGRECORD_TYPE_TRANSACTION_BEGIN: AddTransactionToRecoveryTable(); break; case LOGRECORD_TYPE_TRANSACTION_END: RemoveTransactionFromRecoveryTable(); break; case LOGRECORD_TYPE_TRANSACTION_COMMIT: MoveCommittedTuplesToRecoveryTxn(recovery_txn); break; case LOGRECORD_TYPE_TRANSACTION_ABORT: AbortTuplesFromRecoveryTable(); break; case LOGRECORD_TYPE_ARIES_TUPLE_INSERT: InsertTuple(recovery_txn); break; case LOGRECORD_TYPE_ARIES_TUPLE_DELETE: DeleteTuple(recovery_txn); break; case LOGRECORD_TYPE_ARIES_TUPLE_UPDATE: UpdateTuple(recovery_txn); break; default: reached_end_of_file = true; break; } } // Commit the recovery transaction txn_manager.CommitTransaction(); // Finally, abort ACTIVE transactions in recovery_txn_table AbortActiveTransactions(); // After finishing recovery, set the next oid with maximum oid // observed during the recovery auto &manager = catalog::Manager::GetInstance(); manager.SetNextOid(max_oid); } }
/** * @brief Recovery system based on log file */ void WriteBehindFrontendLogger::DoRecovery() { // Set log file size log_file_size = GetLogFileSize(log_file_fd); // Go over the log size if needed if (log_file_size > 0) { bool reached_end_of_file = false; // check whether first item is LOGRECORD_TYPE_TRANSACTION_COMMIT // if not, no need to do recovery. // if yes, need to replay all log records before we hit // LOGRECORD_TYPE_TRANSACTION_DONE bool need_recovery = NeedRecovery(); if (need_recovery == true) { TransactionRecord dummy_transaction_record(LOGRECORD_TYPE_INVALID); cid_t current_commit_id = INVALID_CID; // Go over each log record in the log file while (reached_end_of_file == false) { // Read the first byte to identify log record type // If that is not possible, then wrap up recovery LogRecordType log_type = GetNextLogRecordType(log_file, log_file_size); switch (log_type) { case LOGRECORD_TYPE_TRANSACTION_DONE: case LOGRECORD_TYPE_TRANSACTION_COMMIT: { // read but do nothing ReadTransactionRecordHeader(dummy_transaction_record, log_file, log_file_size); } break; case LOGRECORD_TYPE_WBL_TUPLE_INSERT: { TupleRecord insert_record(LOGRECORD_TYPE_WBL_TUPLE_INSERT); ReadTupleRecordHeader(insert_record, log_file, log_file_size); auto insert_location = insert_record.GetInsertLocation(); auto info = SetInsertCommitMark(insert_location); current_commit_id = info.first; } break; case LOGRECORD_TYPE_WBL_TUPLE_DELETE: { TupleRecord delete_record(LOGRECORD_TYPE_WBL_TUPLE_DELETE); ReadTupleRecordHeader(delete_record, log_file, log_file_size); auto delete_location = delete_record.GetDeleteLocation(); auto info = SetDeleteCommitMark(delete_location); current_commit_id = info.first; } break; case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: { TupleRecord update_record(LOGRECORD_TYPE_WBL_TUPLE_UPDATE); ReadTupleRecordHeader(update_record, log_file, log_file_size); auto delete_location = update_record.GetDeleteLocation(); SetDeleteCommitMark(delete_location); auto insert_location = update_record.GetInsertLocation(); auto info = SetInsertCommitMark(insert_location); current_commit_id = info.first; } break; default: reached_end_of_file = true; break; } } // Update latest commit id if (latest_commit_id < current_commit_id) { latest_commit_id = current_commit_id; } // write out a trasaction done log record to file // to avoid redo next time during recovery WriteTransactionLogRecord( TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE)); } // After finishing recovery, set the next oid with maximum oid // observed during the recovery auto &manager = catalog::Manager::GetInstance(); manager.SetNextOid(max_oid); } }