作者: 韩晨旭@ArcueidType(Arcueid) 10225101440 李畅@wesley 10225102463 设计文档为PLAN.md,md版本报告为README.md,pdf版本报告为Report.pdf
 
 

183 lines
4.5 KiB

#include "table/vtable_manager.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include <iostream>
#include <ostream>
#include "leveldb/env.h"
#include "leveldb/status.h"
#include "util/coding.h"
namespace leveldb {
struct GCInfo {
std::string dbname;
std::set<uint64_t>* file_list;
Env* env = nullptr;
VTableManager* vtable_manager = nullptr;
};
void VTableMeta::Encode(std::string* target) const {
PutVarint64(target, number);
PutVarint64(target, records_num);
PutVarint64(target, invalid_num);
PutVarint64(target, table_size);
}
Status VTableMeta::Decode(Slice* input) {
if (!GetVarint64(input, &number) || !GetVarint64(input, &records_num) ||
!GetVarint64(input, &invalid_num) || !GetVarint64(input, &table_size)) {
return Status::Corruption("Error Decode VTable meta");
}
return Status::OK();
}
void VTableManager::AddVTable(const VTableMeta& vtable_meta) {
vtables_[vtable_meta.number] = vtable_meta;
}
void VTableManager::RemoveVTable(uint64_t file_num) {
vtables_.erase(file_num);
}
Status VTableManager::AddInvalid(uint64_t file_num) {
const auto it = vtables_.find(file_num);
if (it == vtables_.end()) {
return Status::Corruption("Invalid VTable number");
}
vtables_[file_num].invalid_num += 1;
if (vtables_[file_num].invalid_num >= vtables_[file_num].records_num) {
invalid_.insert(file_num);
}
MaybeScheduleGarbageCollect();
return Status::OK();
}
Status VTableManager::SaveVTableMeta() const {
auto fname = VTableManagerFileName(dbname_);
WritableFile* file;
Status s = env_->NewWritableFile(fname, &file);
if (!s.ok()) {
return Status::Corruption("Failed to open vTable manager file");
}
const auto vtable_num = vtables_.size();
std::string target;
PutVarint64(&target, vtable_num);
for (auto & vtable : vtables_) {
vtable.second.Encode(&target);
}
s = file->Append(target);
if (!s.ok()) {
return Status::Corruption("Failed to append vTable manager file");
}
s = file->Flush();
if (s.ok()) {
s = file->Sync();
}
if (s.ok()) {
s = file->Close();
}
delete file;
file = nullptr;
if (!s.ok()) {
return Status::Corruption("Failed to write vTable meta file");
}
return Status::OK();
}
Status VTableManager::LoadVTableMeta() {
auto fname = VTableManagerFileName(dbname_);
if (!env_->FileExists(fname)) {
return Status::OK();
}
SequentialFile* file;
Status s = env_->NewSequentialFile(fname, &file);
if (!s.ok()) {
return Status::Corruption("Failed to open vTable manager file");
}
uint64_t file_size;
s = env_->GetFileSize(fname, &file_size);
if (!s.ok()) {
return Status::Corruption("Failed to get vTable manager file size");
}
auto buf = new char[file_size];
Slice input;
s = file->Read(file_size, &input, buf);
if (!s.ok()) {
return Status::Corruption("Failed to read vTable manager file");
}
uint64_t vtable_num;
if(!GetVarint64(&input, &vtable_num)) {
return Status::Corruption("Failed to get vTable num");
}
for (int i = 0; i < vtable_num; i++) {
VTableMeta vtable_meta;
s = vtable_meta.Decode(&input);
if (s.ok()) {
if (vtable_meta.number == 0) {
continue;
}
AddVTable(vtable_meta);
if (vtable_meta.invalid_num >= vtable_meta.records_num) {
invalid_.insert(vtable_meta.number);
}
} else {
return s;
}
}
return s;
}
void VTableManager::MaybeScheduleGarbageCollect() {
size_t size = 0;
auto* delete_list = new std::set<uint64_t>();
for (auto & file_num : invalid_) {
size += vtables_[file_num].table_size;
}
if (size >= gc_threshold_) {
auto* gc_info = new GCInfo;
gc_info->dbname = dbname_;
gc_info->file_list = delete_list;
gc_info->env = env_;
gc_info->vtable_manager = this;
env_->StartThread(&VTableManager::BackgroudGC, gc_info);
// for (auto & file_num : gc_info->file_list) {
// RemoveVTable(file_num);
// auto it = std::remove(invalid_.begin(), invalid_.end(), file_num);
// }
}
}
void VTableManager::BackgroudGC(void* gc_info) {
auto info = reinterpret_cast<GCInfo*>(gc_info);
for (auto & file_num : *info->file_list) {
// if (file_num <= 0) {continue;}
auto fname = VTableFileName(info->dbname, file_num);
if (info->vtable_manager->vtables_[file_num].ref <= 0) {
info->env->RemoveFile(fname);
info->vtable_manager->invalid_.erase(file_num);
}
}
}
void VTableManager::RefVTable(uint64_t file_num) {
vtables_[file_num].ref += 1;
}
void VTableManager::UnrefVTable(uint64_t file_num) {
vtables_[file_num].ref -= 1;
}
} // namespace leveldb