|
@ -2,13 +2,13 @@ |
|
|
#include "leveldb/env.h"
|
|
|
#include "leveldb/env.h"
|
|
|
#include "leveldb/db.h"
|
|
|
#include "leveldb/db.h"
|
|
|
#include "leveldb/fields.h"
|
|
|
#include "leveldb/fields.h"
|
|
|
|
|
|
#include "db/filename.h"
|
|
|
#include <iostream>
|
|
|
#include <iostream>
|
|
|
using namespace leveldb; |
|
|
using namespace leveldb; |
|
|
|
|
|
std::string dbName="valuelog_test"; |
|
|
|
|
|
|
|
|
using Field=std::pair<Slice,Slice>; |
|
|
|
|
|
using FieldArray=std::vector<std::pair<Slice, Slice>>; |
|
|
|
|
|
|
|
|
Status OpenDB(DB **db,Options options=Options(),bool destroy_old_db=true) { |
|
|
|
|
|
|
|
|
Status OpenDB(std::string dbName, DB **db,Options options=Options(),bool destroy_old_db=true) { |
|
|
|
|
|
if(destroy_old_db){ |
|
|
if(destroy_old_db){ |
|
|
DestroyDB(dbName,options); |
|
|
DestroyDB(dbName,options); |
|
|
} |
|
|
} |
|
@ -16,6 +16,53 @@ Status OpenDB(std::string dbName, DB **db,Options options=Options(),bool destroy |
|
|
return DB::Open(options, dbName, db); |
|
|
return DB::Open(options, dbName, db); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt,std::string dbname_) { |
|
|
|
|
|
// Pick file to corrupt
|
|
|
|
|
|
std::vector<std::string> filenames; |
|
|
|
|
|
auto env_=Env::Default(); |
|
|
|
|
|
assert(env_->GetChildren(dbname_, &filenames).ok()); |
|
|
|
|
|
uint64_t number; |
|
|
|
|
|
FileType type; |
|
|
|
|
|
std::string fname; |
|
|
|
|
|
int picked_number = 10000000; |
|
|
|
|
|
for (size_t i = 0; i < filenames.size(); i++) { |
|
|
|
|
|
if (ParseFileName(filenames[i], &number, &type) && type == filetype && |
|
|
|
|
|
int(number) < picked_number) { // Pick oldest file
|
|
|
|
|
|
fname = dbname_ + "/" + filenames[i]; |
|
|
|
|
|
picked_number = number; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
ASSERT_TRUE(!fname.empty()) << filetype; |
|
|
|
|
|
|
|
|
|
|
|
uint64_t file_size; |
|
|
|
|
|
ASSERT_TRUE(env_->GetFileSize(fname, &file_size).ok()); |
|
|
|
|
|
|
|
|
|
|
|
if (offset < 0) { |
|
|
|
|
|
// Relative to end of file; make it absolute
|
|
|
|
|
|
if (-offset > file_size) { |
|
|
|
|
|
offset = 0; |
|
|
|
|
|
} else { |
|
|
|
|
|
offset = file_size + offset; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (offset > file_size) { |
|
|
|
|
|
offset = file_size; |
|
|
|
|
|
} |
|
|
|
|
|
if (offset + bytes_to_corrupt > file_size) { |
|
|
|
|
|
bytes_to_corrupt = file_size - offset; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Do it
|
|
|
|
|
|
std::string contents; |
|
|
|
|
|
Status s = ReadFileToString(env_, fname, &contents); |
|
|
|
|
|
ASSERT_TRUE(s.ok()) << s.ToString(); |
|
|
|
|
|
for (int i = 0; i < bytes_to_corrupt; i++) { |
|
|
|
|
|
contents[i + offset] ^= 0x80; |
|
|
|
|
|
} |
|
|
|
|
|
s = WriteStringToFile(env_, contents, fname); |
|
|
|
|
|
ASSERT_TRUE(s.ok()) << s.ToString(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
std::string GenKeyByNum(int num,int len){ |
|
|
std::string GenKeyByNum(int num,int len){ |
|
|
std::string key=std::to_string(num); |
|
|
std::string key=std::to_string(num); |
|
|
while(key.size()<std::to_string(len).size()){ |
|
|
while(key.size()<std::to_string(len).size()){ |
|
@ -62,7 +109,7 @@ TEST(Test, valuelog_iterator_test) { |
|
|
|
|
|
|
|
|
int RANGE=5000; |
|
|
int RANGE=5000; |
|
|
|
|
|
|
|
|
if(OpenDB("valuelog_iterator_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db,dboptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -112,7 +159,7 @@ TEST(Test, mix_valuelog_iterator_test) { |
|
|
|
|
|
|
|
|
int RANGE=5000; |
|
|
int RANGE=5000; |
|
|
|
|
|
|
|
|
if(OpenDB("mix_valuelog_iterator_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db,dboptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -142,11 +189,11 @@ TEST(Test, unorder_valuelog_iterator_test) { |
|
|
WriteOptions writeOptions; |
|
|
WriteOptions writeOptions; |
|
|
ReadOptions readOptions; |
|
|
ReadOptions readOptions; |
|
|
Options dboptions; |
|
|
Options dboptions; |
|
|
dboptions.use_valuelog_length=4000; |
|
|
|
|
|
|
|
|
dboptions.use_valuelog_length=100; |
|
|
|
|
|
|
|
|
int RANGE=5000; |
|
|
int RANGE=5000; |
|
|
|
|
|
|
|
|
if(OpenDB("valuelog_iterator_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db,dboptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -154,7 +201,7 @@ TEST(Test, unorder_valuelog_iterator_test) { |
|
|
std::vector<std::pair<std::string,std::string>> new_values; |
|
|
std::vector<std::pair<std::string,std::string>> new_values; |
|
|
for(int i=0;i<RANGE;i++){ |
|
|
for(int i=0;i<RANGE;i++){ |
|
|
std::string key=GenKeyByNum(i,RANGE); |
|
|
std::string key=GenKeyByNum(i,RANGE); |
|
|
std::string value=GenValueByNum(rand()%2000,1000);//if >1000 then in valuelog(length=4*1000)
|
|
|
|
|
|
|
|
|
std::string value=GenValueByNum(i,1000); |
|
|
values.push_back(value); |
|
|
values.push_back(value); |
|
|
Status s=db->Put(writeOptions,key,value); |
|
|
Status s=db->Put(writeOptions,key,value); |
|
|
assert(s.ok()); |
|
|
assert(s.ok()); |
|
@ -196,7 +243,7 @@ TEST(Test, fields_simple_test) { |
|
|
ReadOptions readOptions; |
|
|
ReadOptions readOptions; |
|
|
Options dbOptions; |
|
|
Options dbOptions; |
|
|
dbOptions.use_valuelog_length=-1; |
|
|
dbOptions.use_valuelog_length=-1; |
|
|
if(OpenDB("fields_simple_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db,dbOptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -227,7 +274,7 @@ TEST(Test, fields_simple_test) { |
|
|
TEST(Test, get_keys_by_field_test) { |
|
|
TEST(Test, get_keys_by_field_test) { |
|
|
DB *db; |
|
|
DB *db; |
|
|
ReadOptions readOptions; |
|
|
ReadOptions readOptions; |
|
|
if(OpenDB("get_keys_by_field_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -262,13 +309,13 @@ TEST(Test, valuelog_common_test) { |
|
|
ReadOptions readOptions; |
|
|
ReadOptions readOptions; |
|
|
Options dbOptions; |
|
|
Options dbOptions; |
|
|
dbOptions.use_valuelog_length=100; |
|
|
dbOptions.use_valuelog_length=100; |
|
|
if(OpenDB("valuelog_common_test", &db).ok() == false) { |
|
|
|
|
|
|
|
|
if(OpenDB(&db,dbOptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
|
//test Put
|
|
|
//test Put
|
|
|
std::vector<std::string> values; |
|
|
std::vector<std::string> values; |
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
std::string value; |
|
|
std::string value; |
|
|
for(int j=0;j<5000;j++){ |
|
|
for(int j=0;j<5000;j++){ |
|
@ -277,7 +324,7 @@ TEST(Test, valuelog_common_test) { |
|
|
values.push_back(value); |
|
|
values.push_back(value); |
|
|
db->Put(writeOptions,key,value); |
|
|
db->Put(writeOptions,key,value); |
|
|
} |
|
|
} |
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
std::string value; |
|
|
std::string value; |
|
|
Status s=db->Get(readOptions,key,&value); |
|
|
Status s=db->Get(readOptions,key,&value); |
|
@ -285,7 +332,7 @@ TEST(Test, valuelog_common_test) { |
|
|
ASSERT_TRUE(values[i]==value); |
|
|
ASSERT_TRUE(values[i]==value); |
|
|
} |
|
|
} |
|
|
//test cover put
|
|
|
//test cover put
|
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
std::string value; |
|
|
std::string value; |
|
|
for(int j=0;j<3000;j++){ |
|
|
for(int j=0;j<3000;j++){ |
|
@ -294,7 +341,7 @@ TEST(Test, valuelog_common_test) { |
|
|
values[i]=value; |
|
|
values[i]=value; |
|
|
db->Put(writeOptions,key,value); |
|
|
db->Put(writeOptions,key,value); |
|
|
} |
|
|
} |
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
std::string value; |
|
|
std::string value; |
|
|
Status s=db->Get(readOptions,key,&value); |
|
|
Status s=db->Get(readOptions,key,&value); |
|
@ -302,11 +349,11 @@ TEST(Test, valuelog_common_test) { |
|
|
ASSERT_TRUE(values[i]==value); |
|
|
ASSERT_TRUE(values[i]==value); |
|
|
} |
|
|
} |
|
|
//test delete
|
|
|
//test delete
|
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
db->Delete(writeOptions,key); |
|
|
db->Delete(writeOptions,key); |
|
|
} |
|
|
} |
|
|
for(int i=0;i<50000;i++){ |
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
|
std::string value; |
|
|
std::string value; |
|
|
Status s=db->Get(readOptions,key,&value); |
|
|
Status s=db->Get(readOptions,key,&value); |
|
@ -315,11 +362,105 @@ TEST(Test, valuelog_common_test) { |
|
|
delete db; |
|
|
delete db; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TEST(Test, Garbage_Collect_TEST) { |
|
|
|
|
|
|
|
|
TEST(Test, valuelog_corruption_test) { |
|
|
DB *db; |
|
|
DB *db; |
|
|
WriteOptions writeOptions; |
|
|
WriteOptions writeOptions; |
|
|
ReadOptions readOptions; |
|
|
ReadOptions readOptions; |
|
|
if(OpenDB("testdb_for_XOY_large", &db).ok() == false) { |
|
|
|
|
|
|
|
|
readOptions.verify_checksums_for_valuelog=true; |
|
|
|
|
|
Options dbOptions; |
|
|
|
|
|
dbOptions.use_valuelog_length=100; |
|
|
|
|
|
dbOptions.valuelog_gc=false; |
|
|
|
|
|
dbOptions.value_log_size=1<<26; |
|
|
|
|
|
dbOptions.valuelog_crc=true; |
|
|
|
|
|
//a record size:8+4+8+4*5000+(4)=20024
|
|
|
|
|
|
//64*1024*1024/20024=3351.42
|
|
|
|
|
|
if(OpenDB(&db,dbOptions).ok() == false) { |
|
|
|
|
|
std::cerr << "open db failed" << std::endl; |
|
|
|
|
|
abort(); |
|
|
|
|
|
} |
|
|
|
|
|
//test Put
|
|
|
|
|
|
std::vector<std::string> values; |
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
for(int j=0;j<5000;j++){ |
|
|
|
|
|
value+=key; |
|
|
|
|
|
} |
|
|
|
|
|
values.push_back(value); |
|
|
|
|
|
db->Put(writeOptions,key,value); |
|
|
|
|
|
} |
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
Status s=db->Get(readOptions,key,&value); |
|
|
|
|
|
assert(s.ok()); |
|
|
|
|
|
ASSERT_TRUE(values[i]==value); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//test corrupt
|
|
|
|
|
|
Corrupt(FileType::kValueLogFile,20100,1,dbName); |
|
|
|
|
|
//the second record is corrupt,
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
if(i!=1)ASSERT_TRUE(db->Get(readOptions,key,&value).ok()); |
|
|
|
|
|
else ASSERT_FALSE(db->Get(readOptions,key,&value).ok()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto iter=db->NewIterator(readOptions); |
|
|
|
|
|
iter->SeekToFirst(); |
|
|
|
|
|
ASSERT_TRUE(iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
iter->Next();//skip 1,to 2
|
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[2]); |
|
|
|
|
|
iter->Seek(GenKeyByNum(1,5000)); |
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[2]); |
|
|
|
|
|
iter->Prev();//skip 1,to 0
|
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[0]); |
|
|
|
|
|
delete iter; |
|
|
|
|
|
|
|
|
|
|
|
db->Put(writeOptions,GenKeyByNum(1,5000),values[1]);//1 is back to normal
|
|
|
|
|
|
|
|
|
|
|
|
//test corrupt on length
|
|
|
|
|
|
Corrupt(FileType::kValueLogFile,20024+20024+2,1,dbName); |
|
|
|
|
|
//the third record is corrupt,
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
if(i!=2)ASSERT_TRUE(db->Get(readOptions,key,&value).ok()); |
|
|
|
|
|
else ASSERT_FALSE(db->Get(readOptions,key,&value).ok()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
iter=db->NewIterator(readOptions); |
|
|
|
|
|
iter->SeekToFirst(); |
|
|
|
|
|
ASSERT_TRUE(iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
iter->Next(); |
|
|
|
|
|
ASSERT_TRUE(iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
iter->Next();//skip 2,to 3
|
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[3]); |
|
|
|
|
|
iter->Seek(GenKeyByNum(2,5000)); |
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[3]); |
|
|
|
|
|
iter->Prev();//skip 2,to 1
|
|
|
|
|
|
ASSERT_TRUE(!iter->status().ok()&&iter->Valid()); |
|
|
|
|
|
ASSERT_TRUE(iter->value()==values[1]); |
|
|
|
|
|
delete iter; |
|
|
|
|
|
delete db; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TEST(Test, garbage_collect_test) { |
|
|
|
|
|
DB *db; |
|
|
|
|
|
WriteOptions writeOptions; |
|
|
|
|
|
ReadOptions readOptions; |
|
|
|
|
|
Options dbOptions; |
|
|
|
|
|
dbOptions.write_buffer_size=1024; |
|
|
|
|
|
dbOptions.max_file_size=8*1024; |
|
|
|
|
|
dbOptions.valuelog_gc=false; |
|
|
|
|
|
if(OpenDB(&db,dbOptions).ok() == false) { |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
std::cerr << "open db failed" << std::endl; |
|
|
abort(); |
|
|
abort(); |
|
|
} |
|
|
} |
|
@ -330,10 +471,44 @@ TEST(Test, Garbage_Collect_TEST) { |
|
|
for(int j=0;j<1000;j++){ |
|
|
for(int j=0;j<1000;j++){ |
|
|
value+=std::to_string(i); |
|
|
value+=std::to_string(i); |
|
|
} |
|
|
} |
|
|
|
|
|
db->Put(writeOptions,key,value); |
|
|
|
|
|
} |
|
|
|
|
|
for(int i=0;i<50000;i++){//make all remaining valuelog worthless, so they will be GC
|
|
|
|
|
|
std::string key=std::to_string(i); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
for(int j=0;j<1001;j++){ |
|
|
|
|
|
value+=std::to_string(i); |
|
|
|
|
|
} |
|
|
values.push_back(value); |
|
|
values.push_back(value); |
|
|
db->Put(writeOptions,key,value); |
|
|
db->Put(writeOptions,key,value); |
|
|
} |
|
|
} |
|
|
|
|
|
std::vector<std::string> origin_filenames; |
|
|
|
|
|
auto env_=Env::Default(); |
|
|
|
|
|
ASSERT_TRUE(env_->GetChildren(dbName, &origin_filenames).ok()); |
|
|
|
|
|
int oldest_valuelog_id=1000; |
|
|
|
|
|
for(auto file:origin_filenames){ |
|
|
|
|
|
uint64_t number; |
|
|
|
|
|
FileType fileType; |
|
|
|
|
|
ParseFileName(file,&number,&fileType); |
|
|
|
|
|
if(fileType==FileType::kValueLogFile&&number<oldest_valuelog_id)oldest_valuelog_id=number; |
|
|
|
|
|
} |
|
|
|
|
|
ASSERT_TRUE(oldest_valuelog_id<1000); |
|
|
|
|
|
|
|
|
|
|
|
db->CompactRange(nullptr,nullptr);//create garbage
|
|
|
db->TEST_GarbageCollect(); |
|
|
db->TEST_GarbageCollect(); |
|
|
|
|
|
db->CompactRange(nullptr,nullptr);//update version
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> new_filenames; |
|
|
|
|
|
ASSERT_TRUE(env_->GetChildren(dbName, &new_filenames).ok()); |
|
|
|
|
|
int oldest_new_valuelog_id=1000; |
|
|
|
|
|
for(auto file:new_filenames){ |
|
|
|
|
|
uint64_t number; |
|
|
|
|
|
FileType fileType; |
|
|
|
|
|
ParseFileName(file,&number,&fileType); |
|
|
|
|
|
if(fileType==FileType::kValueLogFile&&number<oldest_new_valuelog_id)oldest_new_valuelog_id=number; |
|
|
|
|
|
} |
|
|
|
|
|
ASSERT_TRUE(oldest_new_valuelog_id<1000); |
|
|
|
|
|
ASSERT_TRUE(oldest_new_valuelog_id>oldest_valuelog_id);//at least one valuelog file should be deleted
|
|
|
|
|
|
|
|
|
for(int i=0;i<50000;i++){ |
|
|
for(int i=0;i<50000;i++){ |
|
|
std::string key=std::to_string(i); |
|
|
std::string key=std::to_string(i); |
|
@ -345,6 +520,89 @@ TEST(Test, Garbage_Collect_TEST) { |
|
|
delete db; |
|
|
delete db; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
TEST(Test, recovery_test){ |
|
|
|
|
|
DB *db; |
|
|
|
|
|
WriteOptions writeOptions; |
|
|
|
|
|
ReadOptions readOptions; |
|
|
|
|
|
Options dbOptions; |
|
|
|
|
|
dbOptions.write_buffer_size=1024; |
|
|
|
|
|
dbOptions.max_file_size=8*1024; |
|
|
|
|
|
dbOptions.valuelog_gc=false; |
|
|
|
|
|
dbOptions.valuelog_crc=true; |
|
|
|
|
|
dbOptions.use_valuelog_length=100; |
|
|
|
|
|
readOptions.verify_checksums_for_valuelog=true; |
|
|
|
|
|
if(OpenDB(&db,dbOptions).ok() == false) { |
|
|
|
|
|
std::cerr << "open db failed" << std::endl; |
|
|
|
|
|
abort(); |
|
|
|
|
|
} |
|
|
|
|
|
std::vector<std::string> values; |
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
for(int j=0;j<5000;j++){ |
|
|
|
|
|
value+=key; |
|
|
|
|
|
} |
|
|
|
|
|
values.push_back(value); |
|
|
|
|
|
db->Put(writeOptions,key,value); |
|
|
|
|
|
} |
|
|
|
|
|
delete db; |
|
|
|
|
|
if(OpenDB(&db,dbOptions,false).ok() == false) { |
|
|
|
|
|
std::cerr << "open db failed" << std::endl; |
|
|
|
|
|
abort(); |
|
|
|
|
|
} |
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
Status s=db->Get(readOptions,key,&value); |
|
|
|
|
|
assert(s.ok()); |
|
|
|
|
|
ASSERT_TRUE(values[i]==value); |
|
|
|
|
|
} |
|
|
|
|
|
delete db; |
|
|
|
|
|
|
|
|
|
|
|
if(OpenDB(&db,dbOptions,false).ok() == false) { |
|
|
|
|
|
std::cerr << "open db failed" << std::endl; |
|
|
|
|
|
abort(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for(int i=0;i<5000;i++){ |
|
|
|
|
|
std::string key=GenKeyByNum(i,5000); |
|
|
|
|
|
std::string value; |
|
|
|
|
|
for(int j=0;j<5000;j++){ |
|
|
|
|
|
value+=key; |
|
|
|
|
|
} |
|
|
|
|
|
db->Put(writeOptions,key,value); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//test the meta info for gc is still useable
|
|
|
|
|
|
std::vector<std::string> origin_filenames; |
|
|
|
|
|
auto env_=Env::Default(); |
|
|
|
|
|
ASSERT_TRUE(env_->GetChildren(dbName, &origin_filenames).ok()); |
|
|
|
|
|
int oldest_valuelog_id=1000; |
|
|
|
|
|
for(auto file:origin_filenames){ |
|
|
|
|
|
uint64_t number; |
|
|
|
|
|
FileType fileType; |
|
|
|
|
|
ParseFileName(file,&number,&fileType); |
|
|
|
|
|
if(fileType==FileType::kValueLogFile&&number<oldest_valuelog_id)oldest_valuelog_id=number; |
|
|
|
|
|
} |
|
|
|
|
|
ASSERT_TRUE(oldest_valuelog_id<1000); |
|
|
|
|
|
db->CompactRange(nullptr,nullptr);//create garbage
|
|
|
|
|
|
db->TEST_GarbageCollect(); |
|
|
|
|
|
db->CompactRange(nullptr,nullptr);//update version
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> new_filenames; |
|
|
|
|
|
ASSERT_TRUE(env_->GetChildren(dbName, &new_filenames).ok()); |
|
|
|
|
|
int oldest_new_valuelog_id=1000; |
|
|
|
|
|
for(auto file:new_filenames){ |
|
|
|
|
|
uint64_t number; |
|
|
|
|
|
FileType fileType; |
|
|
|
|
|
ParseFileName(file,&number,&fileType); |
|
|
|
|
|
if(fileType==FileType::kValueLogFile&&number<oldest_new_valuelog_id)oldest_new_valuelog_id=number; |
|
|
|
|
|
} |
|
|
|
|
|
ASSERT_TRUE(oldest_new_valuelog_id<1000); |
|
|
|
|
|
ASSERT_TRUE(oldest_new_valuelog_id>oldest_valuelog_id);//at least one valuelog file should be deleted
|
|
|
|
|
|
|
|
|
|
|
|
delete db; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
int main(int argc, char** argv) { |
|
|
// All tests currently run with the same read-only file limits.
|
|
|
// All tests currently run with the same read-only file limits.
|
|
|