// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "db/builder.h"

#include "db/dbformat.h"
#include "db/filename.h"
#include "db/table_cache.h"
#include "db/version_edit.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"

namespace leveldb {

Status BuildTable(const std::string& dbname, Env* env, const Options& options,
                  TableCache* table_cache, Iterator* iter, FileMetaData* meta) {
  Status s;
  meta->file_size = 0;
  iter->SeekToFirst();

  std::string fname = TableFileName(dbname, meta->number);
  if (iter->Valid()) {
    WritableFile* file;
    s = env->NewWritableFile(fname, &file);
    if (!s.ok()) {
      return s;
    }

    time_t nowTime;
    time(&nowTime);
    assert(nowTime > 0);
    
    TableBuilder* builder = new TableBuilder(options, file);
    meta->smallest.DecodeFrom(iter->key());
    Slice key;
    ParsedInternalKey parsed;
    meta->smallest_deadtime = UINT64_MAX;
    meta->largest_deadtime = 0;
    for (; iter->Valid(); iter->Next()) {
      key = iter->key();
      builder->Add(key, iter->value());
      //在构建sstable文件的时候，记录当前文件的生存期最大和最小值,
      //这里要注意internalkey和metadata中对于没有生存期的表示的转换
      ParseInternalKey(key,&parsed);
      if(parsed.deadTime == 0) parsed.deadTime = UINT64_MAX;
      if(parsed.deadTime < nowTime) {
        static int count = 0;
        if(count % 10 == 0) {
          std::cout<<"count "<<count++<<" drop dead in L0: "<<parsed.user_key.ToString()<<" "<<parsed.deadTime<<std::endl;
        }
        continue;
      }
      if(parsed.user_key.ToString() == "16636") {
        printf("specific insert %s deadtime %lu file num %lu\n",parsed.user_key.ToString().c_str(),parsed.deadTime,meta->number);
      }
      meta->smallest_deadtime = std::min(meta->smallest_deadtime,parsed.deadTime);
      meta->largest_deadtime = std::max(meta->largest_deadtime,parsed.deadTime);
    }
    if (!key.empty()) {
      meta->largest.DecodeFrom(key);
    }

    // Finish and check for builder errors
    s = builder->Finish();
    if (s.ok()) {
      meta->file_size = builder->FileSize();
      assert(meta->file_size > 0);
    }
    delete builder;

    // Finish and check for file errors
    if (s.ok()) {
      s = file->Sync();
    }
    if (s.ok()) {
      s = file->Close();
    }
    delete file;
    file = nullptr;

    if (s.ok()) {
      // Verify that the table is usable
      Iterator* it = table_cache->NewIterator(ReadOptions(), meta->number,
                                              meta->file_size);
      s = it->status();
      delete it;
    }
  }

  // Check for input iterator errors
  if (!iter->status().ok()) {
    s = iter->status();
  }

  if (s.ok() && meta->file_size > 0) {
    // Keep it
  } else {
    env->RemoveFile(fname);
  }
  return s;
}

}  // namespace leveldb
