// 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;
  }
}
Example #2
0
/**
 * @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);
}
Example #3
0
/**
 * @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);
  }
}
Example #4
0
/**
 * @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);
  }
}
Example #5
0
/**
 * @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);
  }
}
/**
 * @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);
  }
}