// 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 Add new txn to recovery table */ void AriesFrontendLogger::AddTransactionToRecoveryTable() { // read transaction information from the log file TransactionRecord txn_record(LOGRECORD_TYPE_TRANSACTION_BEGIN); // Check for torn log write if (ReadTransactionRecordHeader(txn_record, log_file, log_file_size) == false) { return; } auto txn_id = txn_record.GetTransactionId(); // create the new txn object and added it into recovery recovery_txn_table concurrency::Transaction *txn = new concurrency::Transaction(txn_id, INVALID_CID); recovery_txn_table.insert(std::make_pair(txn_id, txn)); LOG_TRACE("Added txd id %d object in table", (int)txn_id); }
/** * @brief abort tuple */ void AriesFrontendLogger::AbortTuplesFromRecoveryTable() { // read transaction information from the log file TransactionRecord txn_record(LOGRECORD_TYPE_TRANSACTION_ABORT); // Check for torn log write if (ReadTransactionRecordHeader(txn_record, log_file, log_file_size) == false) { return; } auto txn_id = txn_record.GetTransactionId(); // Get info about the transaction from recovery table if (recovery_txn_table.find(txn_id) != recovery_txn_table.end()) { auto txn = recovery_txn_table.at(txn_id); AbortTuples(txn); LOG_INFO("Abort txd id %d object in table", (int)txn_id); } else { LOG_INFO("Abort txd id %d not found in recovery txn table", (int)txn_id); } }
/** * @brief move tuples from current txn to recovery txn so that we can commit * them later * @param recovery txn */ void AriesFrontendLogger::MoveCommittedTuplesToRecoveryTxn( concurrency::Transaction *recovery_txn) { // read transaction information from the log file TransactionRecord txn_record(LOGRECORD_TYPE_TRANSACTION_COMMIT); // Check for torn log write if (ReadTransactionRecordHeader(txn_record, log_file, log_file_size) == false) { return; } // Get info about the transaction from recovery table auto txn_id = txn_record.GetTransactionId(); if (recovery_txn_table.find(txn_id) != recovery_txn_table.end()) { auto txn = recovery_txn_table.at(txn_id); // Copy inserted/deleted tuples to recovery transaction MoveTuples(recovery_txn, txn); LOG_TRACE("Commit txd id %d object in table", (int)txn_id); } else { LOG_TRACE("Commit txd id %d not found in recovery txn table", (int)txn_id); } }
/** * @brief Remove txn from recovery table */ void AriesFrontendLogger::RemoveTransactionFromRecoveryTable() { // read transaction information from the log file TransactionRecord txn_record(LOGRECORD_TYPE_TRANSACTION_END); // Check for torn log write if (ReadTransactionRecordHeader(txn_record, log_file, log_file_size) == false) { return; } auto txn_id = txn_record.GetTransactionId(); // remove txn from recovery txn table if (recovery_txn_table.find(txn_id) != recovery_txn_table.end()) { auto txn = recovery_txn_table.at(txn_id); recovery_txn_table.erase(txn_id); // drop the txn as well delete txn; LOG_TRACE("Erase txd id %d object in table", (int)txn_id); } else { LOG_TRACE("Erase txd id %d not found in recovery txn table", (int)txn_id); } }