// executed by a single thread. so no synchronization is required.
int TransactionLevelGCManager::Reclaim(const int &thread_id, const cid_t &max_cid) {
  int gc_counter = 0;

  // we delete garbage in the free list
  auto garbage_ctx_entry = reclaim_maps_[thread_id].begin();
  while (garbage_ctx_entry != reclaim_maps_[thread_id].end()) {
    const cid_t garbage_ts = garbage_ctx_entry->first;
    auto garbage_ctx = garbage_ctx_entry->second;

    // if the timestamp of the garbage is older than the current max_cid,
    // recycle it
    if (garbage_ts < max_cid) {
      AddToRecycleMap(garbage_ctx);

      // Remove from the original map
      garbage_ctx_entry = reclaim_maps_[thread_id].erase(garbage_ctx_entry);
      gc_counter++;
    } else {
      // Early break since we use an ordered map
      break;
    }
  }
  LOG_TRACE("Marked %d txn contexts as recycled", gc_counter);
  return gc_counter;
}
Beispiel #2
0
// this function can only be called after:
//    1) All txns have exited
//    2) The background gc thread has exited
void GCManager::ClearGarbage() {
  // iterate reclaim queue and reclaim every thing because it's the end of the world now.
  TupleMetadata tuple_metadata;
  int counter = 0;
  while (reclaim_queue_.Dequeue(tuple_metadata) == true) {
    // In such case, we assume it's the end of the world and every possible
    // garbage is actually garbage
    AddToRecycleMap(tuple_metadata);
    counter++;
  }

  LOG_TRACE("GCManager finally recyle %d tuples", counter);
}
Beispiel #3
0
void GCManager::Running() {
  // Check if we can move anything from the possibly free list to the free list.

  // We use a local buffer to store all possible garbage handled by this gc worker
  std::list<TupleMetadata> local_reclaim_queue;

  while (true) {
    std::this_thread::sleep_for(
        std::chrono::milliseconds(GC_PERIOD_MILLISECONDS));

    LOG_TRACE("reclaim tuple thread...");

    // First load every possible garbage into the list
    // This step move all garbage from the global reclaim queue to the worker's local queue
    for (size_t i = 0; i < MAX_ATTEMPT_COUNT; ++i) {
      TupleMetadata tuple_metadata;
      if (reclaim_queue_.Dequeue(tuple_metadata) == false) {
        break;
      }
      LOG_TRACE("Collect tuple (%u, %u) of table %u into local list",
               tuple_metadata.tile_group_id, tuple_metadata.tuple_slot_id, tuple_metadata.table_id);
      local_reclaim_queue.push_back(tuple_metadata);
    }

    // Then we go through to recycle garbage
    auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
    auto max_cid = txn_manager.GetMaxCommittedCid();

    assert(max_cid != MAX_CID);

    int tuple_counter = 0;
    int attempt = 0;
    auto queue_itr = local_reclaim_queue.begin();

    while (queue_itr != local_reclaim_queue.end() && attempt < MAX_ATTEMPT_COUNT) {
      if (queue_itr->tuple_end_cid <= max_cid) {
        // add the tuple to recycle map
        LOG_TRACE("Add tuple(%u, %u) in table %u to recycle map", queue_itr->tile_group_id,
                 queue_itr->tuple_slot_id, queue_itr->table_id);
        AddToRecycleMap(*queue_itr);
        queue_itr = local_reclaim_queue.erase(queue_itr);
        tuple_counter++;
      } else {
        queue_itr++;
      }
      attempt++;
    }

    LOG_TRACE("Marked %d tuples as garbage", tuple_counter);
    if (is_running_ == false) {
      // Clear all pending garbage
      tuple_counter = 0;
      queue_itr = local_reclaim_queue.begin();

      while (queue_itr != local_reclaim_queue.end()) {
        // In this case, we assume that no transaction is running
        // so every possible garbage is actually garbage
        AddToRecycleMap(*queue_itr);
        queue_itr = local_reclaim_queue.erase(queue_itr);
        tuple_counter ++;
      }

      LOG_TRACE("GCThread recycle last %d tuples before exits", tuple_counter);
      return;
    }
  }
}