#include "leveldb/db.h"
#include "leveldb/filter_policy.h"

#include "leveldb/env.h"
#include "leveldb/db.h"


using namespace leveldb;

constexpr int value_size = 2048;
constexpr int data_size = 128 << 20;

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace leveldb;


// 3. 数据管理（Manifest/创建/恢复数据库）
Status OpenDB(std::string dbName, DB **db) {
  Options options;
  options.create_if_missing = true;
  options.filter_policy = NewBloomFilterPolicy(10);
  return DB::Open(options, dbName, db);
}

// 1. 存储（数据结构与写入）
// 4. 数据合并（Compaction）
//void InsertData(DB *db) {
//  WriteOptions writeOptions;
//  int key_num = data_size / value_size;
//  srand(static_cast<unsigned int>(time(0)));
//
//  for (int i = 0; i < key_num; i++) {
//    int key_ = rand() % key_num+1;
//    std::string key = std::to_string(key_);
//    std::string value(value_size, 'a');
//    db->Put(writeOptions, key, value);
//  }
//}

//void InsertData(DB *db, uint64_t ttl/* second */) {
//  WriteOptions writeOptions;
//  int key_num = data_size / value_size;
//  srand(static_cast<unsigned int>(time(0)));
//  for (int i = 0; i < key_num; i++) {
//    int key_ = rand() % key_num+1;
//    key_ = 1;
//    std::string key = std::to_string(key_);
//    std::string value(value_size, 'a');
//    db->Put(writeOptions, key, value, ttl);
//    std::cout << "time to alive" << ttl << std::endl;
//    break;
//  }
//}

void InsertData(DB *db, uint64_t ttl/* second */) {
  WriteOptions writeOptions;
  int key_num = data_size / value_size;
  srand(0);

  for (int i = 0; i < key_num; i++) {
    int key_ = rand() % key_num+1;
    std::string key = std::to_string(key_);
    std::string value(value_size, 'a');
    db->Put(writeOptions, key, value, ttl);
  }
}
int main(){
  DB *db;

  if(OpenDB("testdb", &db).ok() == false) {
    std::cerr << "open db failed" << std::endl;
    abort();
  }

  uint64_t ttl = 20;
  InsertData(db, ttl);

  leveldb::Range ranges[1];
  ranges[0] = leveldb::Range("-", "A");
  uint64_t sizes[1];
  db->GetApproximateSizes(ranges, 1, sizes);
  //ASSERT_GT(sizes[0], 0);
  assert(sizes[0] > 0);
  Env::Default()->SleepForMicroseconds(ttl * 1000000);

  db->CompactRange(nullptr, nullptr);

  leveldb::Range ranges2[1];
  ranges2[0] = leveldb::Range("-", "A");
  uint64_t sizes2[1];
  db->GetApproximateSizes(ranges2, 1, sizes2);
  assert(sizes2[0] == 0);
}


//int main() {
//
//  DB *db;
//  if(OpenDB("testdb", &db).ok() == false) {
//    std::cerr << "open db failed" << std::endl;
//    abort();
//  }
//
//  uint64_t ttl = 200;
//
////  InsertData(db, ttl);
//  WriteOptions writeOptions;
//  int key_ = 1;
//  std::string key = std::to_string(key_);
//  std::string value(1, 'a');
//  db->Put(writeOptions, key, value, ttl);
//  std::cout << "time to alive" << ttl << std::endl;
//
//  ReadOptions readOptions;
//  std::string value_read;
//  Status status = db->Get(readOptions, key, &value);
//
//
//  //std::cout<<"start sleep for " <<
//  Env::Default()->SleepForMicroseconds(ttl * 100000);
//
//
//  key_ = 1;
//  key = std::to_string(key_);
//  std::string value_read_second;
//  status = db->Get(readOptions, key, &value_read_second);
//  assert(status.ok() != true);
//
//  return 0;
//}

