size_t WriteBehindFrontendLogger::WriteLogRecords(
    std::vector<txn_id_t> committed_txn_list) {
  size_t written_log_record_count = 0;

  // Write out the log records of all the committed transactions to log file
  for (txn_id_t txn_id : committed_txn_list) {
    // Locate the transaction log list for this txn id
    auto txn_log_list =
        global_peloton_log_record_pool.SearchLogRecordList(txn_id);
    if (txn_log_list == nullptr) {
      continue;
    }

    written_log_record_count += txn_log_list->size();

    // Write out all the records in the list
    for (size_t txn_log_list_itr = 0; txn_log_list_itr < txn_log_list->size();
         txn_log_list_itr++) {
      // Write out the log record
      TupleRecord *record = txn_log_list->at(txn_log_list_itr);
      fwrite(record->GetMessage(), sizeof(char), record->GetMessageLength(),
             log_file);
    }
  }

  // No need to flush now, will flush later in WriteTxnLog
  return written_log_record_count;
}
size_t WriteBehindFrontendLogger::WriteLogRecords(
    std::vector<txn_id_t> committed_txn_list) {
  size_t total_txn_log_records = 0;

  // Write out the log records of all the committed transactions to log file
  for (txn_id_t txn_id : committed_txn_list) {
    // Locate the transaction log list for this txn id
    auto exists_txn_log_list =
        global_peloton_log_record_pool.ExistsTxnLogRecordList(txn_id);
    if (exists_txn_log_list == false) {
      continue;
    }

    auto &txn_log_record_list =
        global_peloton_log_record_pool.txn_log_table[txn_id];
    size_t txn_log_record_list_size = txn_log_record_list.size();
    total_txn_log_records += txn_log_record_list_size;

    // Write out all the records in the list
    for (size_t txn_log_list_itr = 0;
         txn_log_list_itr < txn_log_record_list_size; txn_log_list_itr++) {
      TupleRecord *record = txn_log_record_list.at(txn_log_list_itr).get();

      // Write out the log record
      fwrite(record->GetMessage(), sizeof(char), record->GetMessageLength(),
             log_file);
    }
  }

  // No need to flush now, will flush later in WriteTxnLog
  return total_txn_log_records;
}
bool ReadTupleRecordHeader(TupleRecord &tuple_record, FILE *log_file,
                           size_t log_file_size) {
  FileHandle file_handle;
  file_handle.file = log_file;
  file_handle.size = log_file_size;
  file_handle.fd = fileno(file_handle.file);

  // Check if frame is broken
  auto header_size = LoggingUtil::GetNextFrameSize(file_handle);
  if (header_size == 0) {
    LOG_ERROR("Header size is zero ");
    return false;
  }

  // Read header
  char header[header_size];
  size_t ret = fread(header, 1, sizeof(header), file_handle.file);
  if (ret <= 0) {
    LOG_ERROR("Error occured in fread");
  }

  CopySerializeInputBE tuple_header(header, header_size);
  tuple_record.DeserializeHeader(tuple_header);

  return true;
};
/**
 * @brief Read TupleRecordHeader
 * @param tuple_record
 */
bool ReadTupleRecordHeader(TupleRecord &tuple_record, FILE *log_file,
                           size_t log_file_size) {
  // Check if frame is broken
  auto header_size = GetNextFrameSize(log_file, log_file_size);
  if (header_size == 0) {
    LOG_ERROR("Header size is zero ");
    return false;
  }

  // Read header
  char header[header_size];
  size_t ret = fread(header, 1, sizeof(header), log_file);
  if (ret <= 0) {
    LOG_ERROR("Error occured in fread ");
  }

  CopySerializeInputBE tuple_header(header, header_size);
  tuple_record.DeserializeHeader(tuple_header);

  return true;
}
std::set<storage::TileGroupHeader *> WriteBehindFrontendLogger::ToggleCommitMarks(
    std::vector<txn_id_t> committed_txn_list) {
  // Headers modified
  std::set<storage::TileGroupHeader *> tile_group_headers;

  // Toggle commit marks
  for (txn_id_t txn_id : committed_txn_list) {
    auto txn_log_list =
        global_peloton_log_record_pool.SearchLogRecordList(txn_id);
    if (txn_log_list == nullptr) {
      continue;
    }

    for (size_t txn_log_list_itr = 0; txn_log_list_itr < txn_log_list->size();
         txn_log_list_itr++) {
      // Get the log record
      TupleRecord *record = txn_log_list->at(txn_log_list_itr);
      cid_t current_commit_id = INVALID_CID;

      auto record_type = record->GetType();
      switch (record_type) {
        case LOGRECORD_TYPE_WBL_TUPLE_INSERT: {
          // Set insert commit mark
          auto insert_location = record->GetInsertLocation();
          auto info = SetInsertCommitMark(insert_location);
          current_commit_id = info.first;
          tile_group_headers.insert(info.second);
        } break;

        case LOGRECORD_TYPE_WBL_TUPLE_DELETE: {
          // Set delete commit mark
          auto delete_location = record->GetDeleteLocation();
          auto info = SetDeleteCommitMark(delete_location);
          current_commit_id = info.first;
          tile_group_headers.insert(info.second);
        } break;

        case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: {
          // Set delete commit mark
          auto delete_location = record->GetDeleteLocation();
          auto info = SetDeleteCommitMark(delete_location);
          current_commit_id = info.first;
          tile_group_headers.insert(info.second);

          // Set insert commit mark
          auto insert_location = record->GetInsertLocation();
          info = SetInsertCommitMark(insert_location);
          current_commit_id = info.first;
          tile_group_headers.insert(info.second);
        } break;

        default:
          break;
      }

      // Update latest commit id
      if (latest_commit_id < current_commit_id) {
        latest_commit_id = current_commit_id;
      }
    }

    // TODO: All records are committed, its safe to remove them now
    global_peloton_log_record_pool.RemoveTransactionLogList(txn_id);
  }

  return tile_group_headers;
}