/**
 * @brief flush all log records to the file
 */
void WriteBehindFrontendLogger::FlushLogRecords(void) {
  std::vector<txn_id_t> committed_txn_list;
  std::vector<txn_id_t> not_committed_txn_list;
  std::set<oid_t> modified_tile_group_set;

  //===--------------------------------------------------------------------===//
  // Collect the log records
  //===--------------------------------------------------------------------===//

  for (auto record : global_queue) {
    switch (record->GetType()) {
      case LOGRECORD_TYPE_TRANSACTION_BEGIN:
        global_peloton_log_record_pool.CreateTransactionLogList(
            record->GetTransactionId());
        break;

      case LOGRECORD_TYPE_TRANSACTION_COMMIT:
        committed_txn_list.push_back(record->GetTransactionId());
        break;

      case LOGRECORD_TYPE_TRANSACTION_ABORT:
        // Nothing to be done for abort
        break;

      case LOGRECORD_TYPE_TRANSACTION_END:
      case LOGRECORD_TYPE_TRANSACTION_DONE:
        // if a txn is not committed (aborted or active), log records will be
        // removed here
        // Note that list is not be removed immediately, it is removed only
        // after flush and commit.
        not_committed_txn_list.push_back(record->GetTransactionId());
        break;

      case LOGRECORD_TYPE_WBL_TUPLE_INSERT:
      case LOGRECORD_TYPE_WBL_TUPLE_DELETE:
      case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: {
        // Check the commit information,
        auto status =
            CollectTupleRecord(reinterpret_cast<TupleRecord *>(record));

        // Delete record if we did not collect it
        if (status.first == false) {
          delete record;
        }
        // Else, add it to the set of modified tile groups
        else {
          auto location = status.second.block;

          if (location != INVALID_OID) modified_tile_group_set.insert(location);
        }

      } break;

      case LOGRECORD_TYPE_INVALID:
      default:
        throw Exception("Invalid or unrecogized log record found");
        break;
    }
  }

  // Clear the global queue
  global_queue.clear();

  //===--------------------------------------------------------------------===//
  // Write out the log records
  //===--------------------------------------------------------------------===//

  // If committed txn list is not empty
  if (committed_txn_list.empty() == false) {
    //===--------------------------------------------------------------------===//
    // SYNC 1: Sync the TGs
    //===--------------------------------------------------------------------===//

    SyncTileGroups(modified_tile_group_set);

    //===--------------------------------------------------------------------===//
    // SYNC 2: Sync the log for TXN COMMIT record
    //===--------------------------------------------------------------------===//

    // Write out all the committed log records
    size_t written_log_record_count = WriteLogRecords(committed_txn_list);

    // Now, write a committing log entry to file
    // Piggyback the number of written log records as a "txn_id" in this record
    WriteTransactionLogRecord(TransactionRecord(
        LOGRECORD_TYPE_TRANSACTION_COMMIT, written_log_record_count));

    //===--------------------------------------------------------------------===//
    // SYNC 3: Sync the changes to TG headers
    //===--------------------------------------------------------------------===//

    // Toggle the commit marks
    auto tile_group_header_set = ToggleCommitMarks(committed_txn_list);

    // Sync the TG headers
    SyncTileGroupHeaders(tile_group_header_set);

    //===--------------------------------------------------------------------===//
    // SYNC 4 : Sync the log for TXN DONE record
    //===--------------------------------------------------------------------===//

    // Write out a transaction done log record to file
    WriteTransactionLogRecord(
        TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE));
  }

  //===--------------------------------------------------------------------===//
  // Clean up finished transaction log lists
  //===--------------------------------------------------------------------===//

  // remove any finished txn logs
  for (txn_id_t txn_id : not_committed_txn_list) {
    global_peloton_log_record_pool.RemoveTransactionLogList(txn_id);
  }

  // Notify the backend loggers
  {
    std::lock_guard<std::mutex> lock(backend_logger_mutex);
    for (auto backend_logger : backend_loggers) {
      backend_logger->Commit();
    }
  }
}
/**
 * @brief flush all log records to the file
 */
void WriteBehindFrontendLogger::FlushLogRecords(void) {
  std::vector<txn_id_t> committed_txn_list;
  std::vector<txn_id_t> not_committed_txn_list;
  std::set<oid_t> modified_tile_group_set;

  //===--------------------------------------------------------------------===//
  // Collect the log records
  //===--------------------------------------------------------------------===//

  size_t global_queue_size = global_queue.size();
  for (oid_t global_queue_itr = 0; global_queue_itr < global_queue_size;
       global_queue_itr++) {
    if (global_queue[global_queue_itr] == nullptr) {
      continue;
    }

    // FIXME change the interface of write behind logging
    //    switch (global_queue[global_queue_itr]->GetType()) {
    //      case LOGRECORD_TYPE_TRANSACTION_BEGIN:
    //        global_peloton_log_record_pool.CreateTxnLogList(
    //            global_queue[global_queue_itr]->GetTransactionId());
    //        break;
    //
    //      case LOGRECORD_TYPE_TRANSACTION_COMMIT:
    //        committed_txn_list.push_back(
    //            global_queue[global_queue_itr]->GetTransactionId());
    //        break;
    //
    //      case LOGRECORD_TYPE_TRANSACTION_ABORT:
    //        // Nothing to be done for abort
    //        break;
    //
    //      case LOGRECORD_TYPE_TRANSACTION_END:
    //      case LOGRECORD_TYPE_TRANSACTION_DONE:
    //        // if a txn is not committed (aborted or active), log records will
    //        be
    //        // removed here
    //        // Note that list is not be removed immediately, it is removed
    //        only
    //        // after flush and commit.
    //        not_committed_txn_list.push_back(
    //            global_queue[global_queue_itr]->GetTransactionId());
    //        break;
    //
    //      case LOGRECORD_TYPE_WBL_TUPLE_INSERT:
    //      case LOGRECORD_TYPE_WBL_TUPLE_DELETE:
    //      case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: {
    //
    //        LogRecord* log_record = global_queue[global_queue_itr].release();
    //        TupleRecord* tuple_record =
    //        reinterpret_cast<TupleRecord*>(log_record);
    //
    //        // Check the commit information
    //        auto status =
    //            CollectTupleRecord(std::unique_ptr<TupleRecord>(tuple_record));
    //
    //        // Add it to the set of modified tile groups
    //        if (status.first == true) {
    //          auto location = status.second.block;
    //          if (location != INVALID_OID) {
    //            modified_tile_group_set.insert(location);
    //          }
    //        }
    //
    //      } break;
    //
    //      case LOGRECORD_TYPE_INVALID:
    //      default:
    //        throw Exception("Invalid or unrecogized log record found");
    //        break;
    //    }
  }

  // Clean up the frontend logger's queue
  global_queue.clear();

  //===--------------------------------------------------------------------===//
  // Write out the log records
  //===--------------------------------------------------------------------===//

  // If committed txn list is not empty
  if (committed_txn_list.empty() == false) {
    //===--------------------------------------------------------------------===//
    // SYNC 1: Sync the TGs
    //===--------------------------------------------------------------------===//

    SyncTileGroups(modified_tile_group_set);

    //===--------------------------------------------------------------------===//
    // SYNC 2: Sync the log for TXN COMMIT record
    //===--------------------------------------------------------------------===//

    // Write out all the committed log records
    size_t written_log_record_count = WriteLogRecords(committed_txn_list);

    // Now, write a committing log entry to file
    // Piggyback the number of written log records as a "txn_id" in this record
    WriteTransactionLogRecord(TransactionRecord(
        LOGRECORD_TYPE_TRANSACTION_COMMIT, written_log_record_count));

    //===--------------------------------------------------------------------===//
    // SYNC 3: Sync the changes to TG headers
    //===--------------------------------------------------------------------===//

    // Toggle the commit marks
    auto tile_group_header_set = ToggleCommitMarks(committed_txn_list);

    // Sync the TG headers
    SyncTileGroupHeaders(tile_group_header_set);

    //===--------------------------------------------------------------------===//
    // SYNC 4 : Sync the log for TXN DONE record
    //===--------------------------------------------------------------------===//

    // Write out a transaction done log record to file
    WriteTransactionLogRecord(
        TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE));
  }

  //===--------------------------------------------------------------------===//
  // Clean up finished transaction log lists
  //===--------------------------------------------------------------------===//

  // remove any finished txn logs
  for (txn_id_t txn_id : not_committed_txn_list) {
    global_peloton_log_record_pool.RemoveTxnLogRecordList(txn_id);
  }

  // Notify the backend loggers
  //  {
  //    for (auto backend_logger : backend_loggers) {
  //      // FIXME
  //      assert(backend_logger);
  //      // backend_logger->FinishedFlushing();
  //    }
  //  }
}