//
// Created by 马也驰 on 2024/12/29.
//

#ifndef LEVELDB_VLOG_GC_H
#define LEVELDB_VLOG_GC_H


#include <string>
#include <mutex>
#include <thread>
#include <chrono>
#include "../db/slotpage.h"
#include "../db/vlog.h"
#include "../db/gc_executor.h"

// 前向声明 VlogSet
class VlogSet;

class VlogGC {
#define THREAD_NUM  8
friend class gc_executor;

 public:
  VlogGC(SlotPage *s, VlogSet *vs) : slot_page_(s), vlog_set(vs),max_thread_nums_(THREAD_NUM),
                                     curr_thread_nums_(0), gc_num(0) {}
  ~VlogGC() {
    while (true) {
      curr_thread_nums_latch_.lock();
      if (curr_thread_nums_) {
        curr_thread_nums_latch_.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
      } else {
        curr_thread_nums_latch_.unlock();
        break;
      }
    }
    std::cout << "vlog_gc has been deleted!" << std::endl;
  }

  void do_gc(size_t old_vlog_num, size_t new_vlog_num);

  SlotPage *get_slot_page() { return slot_page_; }
  VlogSet *get_vlog_set() { return vlog_set; }


 private:
  void exec_gc(size_t gc_num_);
//  static void gc_process(VlogGC *vlog_gc_, size_t old_vlog_num, size_t new_vlog_num);
  void gc_counter_increment();
  void gc_counter_decrement();

//  static inline bool value_deleted(uint16_t value_len) {
//    return !(value_len >> 15);
//  }
//  static inline uint16_t get_value_len(char *value) {
//    uint16_t value_len;
//    memcpy(&value_len, value, sizeof(uint16_t));
//    return value_len;
//  }
//  static inline size_t get_value_slotnum(char *value) {
//    size_t slot_num;
//    memcpy(&slot_num, &value[sizeof(uint16_t)], sizeof(size_t));
//    return slot_num;
//  }

  inline size_t get_gc_num() {
    gc_num_latch_.lock();
    size_t _gc_num_ = gc_num ++;
    gc_num_latch_.unlock();
    return _gc_num_;
  }

  inline bool vlog_in_gc(size_t vlog_num) {
    ovn_map_latch_.lock();
    bool flag = false;
    if (ovn_map_.find(vlog_num) != ovn_map_.end()) {
      flag = true;
    }
    ovn_map_latch_.unlock();
    return flag;
  }
  inline void add_vlog_in_gc(size_t vlog_num) {
    ovn_map_latch_.lock();
    ovn_map_[vlog_num] = true;
    ovn_map_latch_.unlock();
  }
  inline void del_vlog_in_gc(size_t vlog_num) {
    ovn_map_latch_.lock();
    ovn_map_.erase(vlog_num);
    ovn_map_latch_.unlock();
  }

 private:
  SlotPage *slot_page_;
  VlogSet *vlog_set;  // 仅声明为指针，具体定义放在 vlog_gc.cpp

  // NOTE: threadpool
  std::mutex full_latch_; // indicate thread pool is full when set as locked
  size_t max_thread_nums_;
  std::mutex curr_thread_nums_latch_;
  size_t curr_thread_nums_;

  // 避免重复gc
  std::mutex gc_num_latch_;
  size_t gc_num;  // gc线程id，不断增长，方便从全局map中获取gc参数等信息

  std::mutex ovn_map_latch_;
  std::unordered_map<size_t, bool> ovn_map_; // 表明某个vlog是否正在进行gc
};


#endif  // LEVELDB_VLOG_GC_H
