|
|
@ -4,10 +4,13 @@ |
|
|
|
|
|
|
|
#include "db/db_impl.h"
|
|
|
|
|
|
|
|
#include "db/version_edit.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <atomic>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
@ -24,10 +27,17 @@ |
|
|
|
#include "db/write_batch_internal.h"
|
|
|
|
#include "leveldb/db.h"
|
|
|
|
#include "leveldb/env.h"
|
|
|
|
#include "leveldb/filter_policy.h"
|
|
|
|
#include "leveldb/iterator.h"
|
|
|
|
#include "leveldb/options.h"
|
|
|
|
#include "leveldb/slice.h"
|
|
|
|
#include "leveldb/status.h"
|
|
|
|
#include "leveldb/table.h"
|
|
|
|
#include "leveldb/table_builder.h"
|
|
|
|
#include "leveldb/write_batch.h"
|
|
|
|
#include "port/port.h"
|
|
|
|
#include "port/port_stdcxx.h"
|
|
|
|
#include "port/thread_annotations.h"
|
|
|
|
#include "table/block.h"
|
|
|
|
#include "table/merger.h"
|
|
|
|
#include "table/two_level_iterator.h"
|
|
|
@ -35,6 +45,7 @@ |
|
|
|
#include "util/logging.h"
|
|
|
|
#include "util/mutexlock.h"
|
|
|
|
#include "util/serialize_value.h"
|
|
|
|
#include "kv_sep/kvlog.h"
|
|
|
|
|
|
|
|
namespace leveldb { |
|
|
|
|
|
|
@ -145,6 +156,7 @@ DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) |
|
|
|
log_(nullptr), |
|
|
|
seed_(0), |
|
|
|
tmp_batch_(new WriteBatch), |
|
|
|
tmp_kp_batch_(new WriteBatch), |
|
|
|
background_compaction_scheduled_(false), |
|
|
|
manual_compaction_(nullptr), |
|
|
|
versions_(new VersionSet(dbname_, &options_, table_cache_, |
|
|
@ -235,6 +247,8 @@ void DBImpl::RemoveObsoleteFiles() { |
|
|
|
// Make a set of all of the live files
|
|
|
|
std::set<uint64_t> live = pending_outputs_; |
|
|
|
versions_->AddLiveFiles(&live); |
|
|
|
//将所有的live的kvlog加入集合,防止被删除
|
|
|
|
versions_->AddLiveKVLogs(&live); |
|
|
|
|
|
|
|
std::vector<std::string> filenames; |
|
|
|
env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose
|
|
|
@ -262,6 +276,9 @@ void DBImpl::RemoveObsoleteFiles() { |
|
|
|
// be recorded in pending_outputs_, which is inserted into "live"
|
|
|
|
keep = (live.find(number) != live.end()); |
|
|
|
break; |
|
|
|
case kKVLogFile: |
|
|
|
keep = (live.find(number) != live.end()); |
|
|
|
break; |
|
|
|
case kCurrentFile: |
|
|
|
case kDBLockFile: |
|
|
|
case kInfoLogFile: |
|
|
@ -533,13 +550,18 @@ Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, |
|
|
|
if (s.ok() && meta.file_size > 0) { |
|
|
|
const Slice min_user_key = meta.smallest.user_key(); |
|
|
|
const Slice max_user_key = meta.largest.user_key(); |
|
|
|
if (base != nullptr) { |
|
|
|
if (base != nullptr && !only_Level0) { |
|
|
|
level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); |
|
|
|
} |
|
|
|
edit->AddFile(level, meta.number, meta.file_size, meta.smallest, |
|
|
|
meta.largest); |
|
|
|
} |
|
|
|
|
|
|
|
edit->AddKVLogs(imm_kvlogfile_number); |
|
|
|
pending_outputs_.erase(imm_kvlogfile_number); |
|
|
|
imm_kvlogfile_number = 0; |
|
|
|
delete imm_kvlogfile_; |
|
|
|
|
|
|
|
CompactionStats stats; |
|
|
|
stats.micros = env_->NowMicros() - start_micros; |
|
|
|
stats.bytes_written = meta.file_size; |
|
|
@ -705,6 +727,155 @@ void DBImpl::BackgroundCall() { |
|
|
|
background_work_finished_signal_.SignalAll(); |
|
|
|
} |
|
|
|
|
|
|
|
bool DBImpl::CollectKVLogs() { |
|
|
|
mutex_.AssertHeld(); |
|
|
|
Version *current = versions_->current(); |
|
|
|
current->Ref(); |
|
|
|
int total_files = 0; |
|
|
|
for(int i = 0; i < config::kNumLevels; i++) { |
|
|
|
total_files += current->NumFiles(i); |
|
|
|
} |
|
|
|
//这个判断保证了所有被选择回收的kvlog都是不对应于mem、imm、L0文件的
|
|
|
|
if(current->kvlogs_.size() < total_files * 20) { |
|
|
|
// std::cout << "kvlogs not enough : " << current->kvlogs_.size() << " " << total_files << std::endl;
|
|
|
|
current->Unref(); |
|
|
|
return false; |
|
|
|
} |
|
|
|
Log(options_.info_log,"CollectKVLogs Start\n"); |
|
|
|
std::vector<FileMetaData*> &kvlogs = current->kvlogs_; |
|
|
|
|
|
|
|
FileMetaData metaSST, metaKVLog; |
|
|
|
metaSST.number = versions_->NewFileNumber(); |
|
|
|
metaKVLog.number = versions_->NewFileNumber(); |
|
|
|
pending_outputs_.insert(metaSST.number); |
|
|
|
pending_outputs_.insert(metaKVLog.number); |
|
|
|
|
|
|
|
// WritableFile *fileSST;
|
|
|
|
// env_->NewWritableFile(TableFileName(dbname_, metaSST.number),&fileSST);
|
|
|
|
// TableBuilder *builder = new TableBuilder(options_,fileSST);
|
|
|
|
|
|
|
|
WritableFile *fileKVLog; |
|
|
|
env_->NewWritableFile(KVLogFileName(dbname_, metaKVLog.number), &fileKVLog); |
|
|
|
KVLog kvlog_writer(fileKVLog,metaKVLog.number); |
|
|
|
FilePointer fp; |
|
|
|
|
|
|
|
uint32_t seed; |
|
|
|
SequenceNumber latest_sequence; |
|
|
|
ReadOptions ro; |
|
|
|
ro.decode = false; |
|
|
|
Iterator *deep_iter = NewInternalDeepIterator(ro,&latest_sequence,&seed); |
|
|
|
// Iterator *iter = NewDBIterator(this, user_comparator(), deep_iter, latest_sequence, seed);
|
|
|
|
|
|
|
|
uint64_t budget = 100; |
|
|
|
only_Level0 = true; //保证后续的小合并的结果只会在level0
|
|
|
|
mutex_.Unlock(); |
|
|
|
|
|
|
|
std::string saved_key_; |
|
|
|
// ParsedInternalKey key_in_kvlog;
|
|
|
|
ParsedInternalKey key_in_sst; |
|
|
|
WriteBatch write_batch,kp_batch; |
|
|
|
MemTable *tempMem = new MemTable(internal_comparator_); |
|
|
|
tempMem->Ref(); |
|
|
|
std::set<uint64_t> kvlogs_to_remove; |
|
|
|
bool has_collected = false; |
|
|
|
|
|
|
|
for(int i = 0; i < std::min(kvlogs.size(),20ul) && budget > 0; i++) { |
|
|
|
FileMetaData *f = kvlogs[i]; |
|
|
|
SequentialFile *file; |
|
|
|
env_->NewSequentialFile(KVLogFileName(dbname_, f->number), &file); |
|
|
|
KVLogReader reader(file); |
|
|
|
for(int cnt = 0; reader.Valid(); reader.Next(), cnt ++) { |
|
|
|
// std::cout << "find KV: " << reader.Key().ToString() << " " << reader.Value().ToString() << " " << reader.Seq() << "\n";
|
|
|
|
if(reader.Type() == kTypeDeletion) { |
|
|
|
// std::cout << "is delete record\n";
|
|
|
|
continue; |
|
|
|
} |
|
|
|
saved_key_.clear(); |
|
|
|
AppendInternalKey(&saved_key_, |
|
|
|
ParsedInternalKey(reader.Key(),latest_sequence,kValueTypeForSeek,metaKVLog.number)); |
|
|
|
deep_iter->Seek(saved_key_); |
|
|
|
|
|
|
|
// ParseInternalKey(reader.Key(), &key_in_kvlog);
|
|
|
|
ParseInternalKey(deep_iter->key(), &key_in_sst); |
|
|
|
//当前的key已经由于合并没有了,kvlog中的记录失效
|
|
|
|
if(internal_comparator_.user_comparator()->Compare(reader.Key(), key_in_sst.user_key) != 0) { |
|
|
|
// std::cout << "has been compacted\n";
|
|
|
|
continue; |
|
|
|
} |
|
|
|
//如果搜索到的key是delete,或者key的sequence比kvlog里面的大,那么kvlog中的就是失效状态
|
|
|
|
//这里不可能搜到比kvlog里面还要小的情况
|
|
|
|
if(key_in_sst.type == kTypeDeletion) { |
|
|
|
// std::cout << "key delete \n";
|
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if(key_in_sst.sequence > reader.Seq()) { |
|
|
|
// printf("sst seq larger: sst:%ld kvlog:%ld\n",key_in_sst.sequence,reader.Seq());
|
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if(i > 0) { |
|
|
|
budget = 0; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
has_collected = true; |
|
|
|
// std::cout << "collected KV: " << reader.Key().ToString() << " " << reader.Value().ToString() << " " << reader.Seq() << "\n";
|
|
|
|
// if(budget % 100 == 0) {
|
|
|
|
// std::cout << "collected KV: " << reader.Value().ToString() << " " << reader.Seq() << " " << cnt << "\n";
|
|
|
|
// std::cout << "rest budget : " << budget << "\n";
|
|
|
|
// }
|
|
|
|
budget--; |
|
|
|
write_batch.Clear(); |
|
|
|
kp_batch.Clear(); |
|
|
|
write_batch.Put(reader.Key(), reader.Value()); |
|
|
|
WriteBatchInternal::SetSequence(&write_batch, reader.Seq()); |
|
|
|
kvlog_writer.AddRecord(WriteBatchInternal::Contents(&write_batch), fp); |
|
|
|
WriteBatchInternal::ConstructKPBatch(&kp_batch, &write_batch, fp); |
|
|
|
WriteBatchInternal::InsertInto(&kp_batch, tempMem); |
|
|
|
} |
|
|
|
delete file; |
|
|
|
if(reader.Valid()) break; |
|
|
|
kvlogs_to_remove.insert(f->number); |
|
|
|
// break;//当前一次只回收一个kvlog
|
|
|
|
} |
|
|
|
|
|
|
|
VersionEdit edit; |
|
|
|
Iterator *miter = nullptr; |
|
|
|
if(has_collected) { |
|
|
|
miter = tempMem->NewIterator(); |
|
|
|
Status s = BuildTable(dbname_, env_, options_, |
|
|
|
table_cache_, miter, &metaSST); |
|
|
|
} |
|
|
|
mutex_.Lock(); |
|
|
|
if(has_collected) { |
|
|
|
edit.AddFile(0, metaSST.number, metaSST.file_size, |
|
|
|
metaSST.smallest, metaSST.largest); |
|
|
|
edit.AddKVLogs(metaKVLog.number); |
|
|
|
} |
|
|
|
for(auto num : kvlogs_to_remove) { |
|
|
|
edit.RemoveKVLogs(num); |
|
|
|
} |
|
|
|
Log(options_.info_log,"Add SST at Level0 : %ld\n",metaSST.number); |
|
|
|
for(auto num : kvlogs_to_remove) { |
|
|
|
Log(options_.info_log,"Collect kvlog : %ld\n",num); |
|
|
|
printf("Collect kvlog : %ld\n",num); |
|
|
|
} |
|
|
|
Log(options_.info_log,"Merge to kvlog : %ld\n",metaKVLog.number); |
|
|
|
|
|
|
|
versions_->LogAndApply(&edit, &mutex_); |
|
|
|
|
|
|
|
delete miter; |
|
|
|
tempMem->Unref(); |
|
|
|
delete deep_iter; |
|
|
|
delete fileKVLog; |
|
|
|
pending_outputs_.erase(metaSST.number); |
|
|
|
pending_outputs_.erase(metaKVLog.number); |
|
|
|
only_Level0 = false; |
|
|
|
current->Unref(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void DBImpl::BackgroundCompaction() { |
|
|
|
mutex_.AssertHeld(); |
|
|
|
|
|
|
@ -713,6 +884,10 @@ void DBImpl::BackgroundCompaction() { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if(CollectKVLogs()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
Compaction* c; |
|
|
|
bool is_manual = (manual_compaction_ != nullptr); |
|
|
|
InternalKey manual_end; |
|
|
@ -1078,6 +1253,20 @@ static void CleanupIteratorState(void* arg1, void* arg2) { |
|
|
|
delete state; |
|
|
|
} |
|
|
|
|
|
|
|
struct DeepIterState { |
|
|
|
port::Mutex* const mu; |
|
|
|
Version* const version GUARDED_BY(mu); |
|
|
|
DeepIterState(port::Mutex* mutex, Version* version) |
|
|
|
: mu(mutex),version(version) {} |
|
|
|
}; |
|
|
|
|
|
|
|
static void CleanupDeepIteratorState(void* arg1, void* args) { |
|
|
|
DeepIterState* state = reinterpret_cast<DeepIterState*>(arg1); |
|
|
|
state->mu->AssertHeld(); |
|
|
|
state->version->Unref(); |
|
|
|
delete state; |
|
|
|
} |
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, |
|
|
@ -1107,6 +1296,33 @@ Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, |
|
|
|
return internal_iter; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//在初始化和析构的时候都要保证mutex_.AssertHeld()
|
|
|
|
Iterator* DBImpl::NewInternalDeepIterator(const ReadOptions& options, |
|
|
|
SequenceNumber* latest_snapshot, |
|
|
|
uint32_t* seed) { |
|
|
|
mutex_.AssertHeld(); |
|
|
|
// mutex_.Lock();
|
|
|
|
*latest_snapshot = versions_->LastSequence(); |
|
|
|
|
|
|
|
// Collect together all needed child iterators
|
|
|
|
std::vector<Iterator*> list; |
|
|
|
|
|
|
|
versions_->current()->AddDeepIterators(options, &list); |
|
|
|
Iterator* internal_iter = |
|
|
|
NewMergingIterator(&internal_comparator_, &list[0], list.size()); |
|
|
|
versions_->current()->Ref(); |
|
|
|
|
|
|
|
// IterState* cleanup = new IterState(&mutex_, mem_, imm_, versions_->current());
|
|
|
|
// internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr);
|
|
|
|
|
|
|
|
DeepIterState *cleanup = new DeepIterState(&mutex_,versions_->current()); |
|
|
|
internal_iter->RegisterCleanup(CleanupDeepIteratorState, cleanup, nullptr); |
|
|
|
*seed = ++seed_; |
|
|
|
// mutex_.Unlock();
|
|
|
|
return internal_iter; |
|
|
|
} |
|
|
|
|
|
|
|
Iterator* DBImpl::TEST_NewInternalIterator() { |
|
|
|
SequenceNumber ignored; |
|
|
|
uint32_t ignored_seed; |
|
|
@ -1118,6 +1334,18 @@ int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { |
|
|
|
return versions_->MaxNextLevelOverlappingBytes(); |
|
|
|
} |
|
|
|
|
|
|
|
Slice DBImpl::GetValueFromFP(const FilePointer &fp,std::string *value) { |
|
|
|
RandomAccessFile *file; |
|
|
|
Status s = env_->NewRandomAccessFile(KVLogFileName(dbname_, fp.FileNumber), &file); |
|
|
|
Slice slice; |
|
|
|
char *buf = new char[fp.Size]; |
|
|
|
s = file->Read(fp.FileOffset, fp.Size, &slice, buf); |
|
|
|
*value = slice.ToString(); |
|
|
|
delete[] buf; |
|
|
|
delete file; |
|
|
|
return slice; |
|
|
|
} |
|
|
|
|
|
|
|
Status DBImpl::Get(const ReadOptions& options, const Slice& key, |
|
|
|
std::string* value) { |
|
|
|
Status s; |
|
|
@ -1159,6 +1387,15 @@ Status DBImpl::Get(const ReadOptions& options, const Slice& key, |
|
|
|
if (have_stat_update && current->UpdateStats(stats)) { |
|
|
|
MaybeScheduleCompaction(); |
|
|
|
} |
|
|
|
if(!s.ok()) { |
|
|
|
// printf( "not found : %s\n",key.ToString().c_str());
|
|
|
|
} else { |
|
|
|
// printf("found key:%s value:%s\n",key.ToString().c_str(),value->c_str());
|
|
|
|
FilePointer fp; |
|
|
|
DecodeFp(fp, value->data()); |
|
|
|
GetValueFromFP(fp, value); |
|
|
|
} |
|
|
|
|
|
|
|
mem->Unref(); |
|
|
|
if (imm != nullptr) imm->Unref(); |
|
|
|
current->Unref(); |
|
|
@ -1252,12 +1489,13 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { |
|
|
|
|
|
|
|
// May temporarily unlock and wait.
|
|
|
|
Status status = MakeRoomForWrite(updates == nullptr); |
|
|
|
uint64_t last_sequence = versions_->LastSequence(); |
|
|
|
uint64_t last_sequence = versions_->LastSequence(), temp_seq = last_sequence; |
|
|
|
Writer* last_writer = &w; |
|
|
|
if (status.ok() && updates != nullptr) { // nullptr batch is for compactions
|
|
|
|
WriteBatch* write_batch = BuildBatchGroup(&last_writer); |
|
|
|
WriteBatchInternal::SetSequence(write_batch, last_sequence + 1); |
|
|
|
last_sequence += WriteBatchInternal::Count(write_batch); |
|
|
|
// versions_->SetLastSequence(last_sequence);
|
|
|
|
|
|
|
|
// Add to log and apply to memtable. We can release the lock
|
|
|
|
// during this phase since &w is currently responsible for logging
|
|
|
@ -1266,7 +1504,14 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { |
|
|
|
{ |
|
|
|
mutex_.Unlock(); |
|
|
|
// uint64_t start_write = env_->NowMicros();
|
|
|
|
status = log_->AddRecord(WriteBatchInternal::Contents(write_batch)); |
|
|
|
FilePointer fp; |
|
|
|
//1. 将WriteBatch写入到kvlog中
|
|
|
|
status = kvlog_->AddRecord(WriteBatchInternal::Contents(write_batch), fp); |
|
|
|
//2. 将writebatch的filepointer写入到log中
|
|
|
|
// status = log_->AddRecord(WriteBatchInternal::Contents(write_batch));
|
|
|
|
char rep[8 * 3]; |
|
|
|
EncodeFP(fp, rep); |
|
|
|
status = log_->AddRecord(Slice(rep, 3 * 8)); |
|
|
|
bool sync_error = false; |
|
|
|
if (status.ok() && options.sync) { |
|
|
|
status = logfile_->Sync(); |
|
|
@ -1274,8 +1519,11 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { |
|
|
|
sync_error = true; |
|
|
|
} |
|
|
|
} |
|
|
|
//3. 根据write_batch里面的内容,构建kp_batch
|
|
|
|
WriteBatchInternal::ConstructKPBatch(tmp_kp_batch_, write_batch, fp); |
|
|
|
WriteBatchInternal::SetSequence(tmp_kp_batch_,temp_seq + 1); |
|
|
|
if (status.ok()) { |
|
|
|
status = WriteBatchInternal::InsertInto(write_batch, mem_); |
|
|
|
status = WriteBatchInternal::InsertInto(tmp_kp_batch_, mem_); |
|
|
|
} |
|
|
|
// BatchSize += write_batch->ApproximateSize();
|
|
|
|
// write_elapsed += env_->NowMicros() - start_write;
|
|
|
@ -1311,6 +1559,15 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { |
|
|
|
// NoWaiting_elapsed += env_->NowMicros() - start_;
|
|
|
|
// Nowaited_count ++;
|
|
|
|
// dumpStatistics();
|
|
|
|
// SequentialFile *file;
|
|
|
|
// env_->NewSequentialFile(KVLogFileName(dbname_, kvlogfile_number_), &file);
|
|
|
|
// KVLogReader reader(file);
|
|
|
|
// std::cout << "==============tail check begin==============\n";
|
|
|
|
// for( ;reader.Valid(); reader.Next()) {
|
|
|
|
// printf("key:%s, value:%s, seq:%ld\n",reader.Key().ToString().c_str(),reader.Value().ToString().c_str(),reader.Seq());
|
|
|
|
// }
|
|
|
|
// std::cout << "==============tail check end==============\n";
|
|
|
|
// delete file;
|
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
@ -1412,6 +1669,22 @@ Status DBImpl::MakeRoomForWrite(bool force) { |
|
|
|
versions_->ReuseFileNumber(new_log_number); |
|
|
|
break; |
|
|
|
} |
|
|
|
/*更换新的kvlog*/ |
|
|
|
uint64_t new_kvlog_number = versions_->NewFileNumber(); |
|
|
|
WritableFile* kvlogfile = nullptr; |
|
|
|
s = env_->NewWritableFile(KVLogFileName(dbname_,new_kvlog_number),&kvlogfile); |
|
|
|
if(!s.ok()) { |
|
|
|
versions_->ReuseFileNumber(new_kvlog_number); |
|
|
|
break; |
|
|
|
} |
|
|
|
pending_outputs_.insert(new_kvlog_number); |
|
|
|
kvlogfile_->Close(); |
|
|
|
imm_kvlogfile_ = kvlogfile_; |
|
|
|
kvlogfile_ = kvlogfile; |
|
|
|
imm_kvlogfile_number = kvlogfile_number_; |
|
|
|
kvlogfile_number_ = new_kvlog_number; |
|
|
|
delete kvlog_; |
|
|
|
kvlog_ = new KVLog(kvlogfile,new_kvlog_number); |
|
|
|
|
|
|
|
delete log_; |
|
|
|
|
|
|
@ -1566,6 +1839,14 @@ Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) { |
|
|
|
impl->mem_ = new MemTable(impl->internal_comparator_); |
|
|
|
impl->mem_->Ref(); |
|
|
|
} |
|
|
|
|
|
|
|
uint64_t new_kvlog_number = impl->versions_->NewFileNumber(); |
|
|
|
WritableFile* kvlogfile; |
|
|
|
s = options.env->NewWritableFile(KVLogFileName(dbname, new_kvlog_number), &kvlogfile); |
|
|
|
impl->pending_outputs_.insert(new_kvlog_number); |
|
|
|
impl->kvlogfile_number_ = new_kvlog_number; |
|
|
|
impl->kvlogfile_ = kvlogfile; |
|
|
|
impl->kvlog_ = new KVLog(kvlogfile,new_kvlog_number); |
|
|
|
} |
|
|
|
if (s.ok() && save_manifest) { |
|
|
|
edit.SetPrevLogNumber(0); // No older logs needed after recovery.
|
|
|
@ -1607,6 +1888,7 @@ Status DestroyDB(const std::string& dbname, const Options& options) { |
|
|
|
if (ParseFileName(filenames[i], &number, &type) && |
|
|
|
type != kDBLockFile) { // Lock file will be deleted at end
|
|
|
|
Status del = env->RemoveFile(dbname + "/" + filenames[i]); |
|
|
|
// std::cout << "remove file : " << filenames[i] << std::endl;
|
|
|
|
if (result.ok() && !del.ok()) { |
|
|
|
result = del; |
|
|
|
} |
|
|
|