1*9507f98cSAndroid Build Coastguard Worker // Copyright (c) 2014 The LevelDB Authors. All rights reserved.
2*9507f98cSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*9507f98cSAndroid Build Coastguard Worker // found in the LICENSE file. See the AUTHORS file for names of contributors.
4*9507f98cSAndroid Build Coastguard Worker
5*9507f98cSAndroid Build Coastguard Worker #include "gtest/gtest.h"
6*9507f98cSAndroid Build Coastguard Worker #include "db/db_impl.h"
7*9507f98cSAndroid Build Coastguard Worker #include "db/filename.h"
8*9507f98cSAndroid Build Coastguard Worker #include "db/version_set.h"
9*9507f98cSAndroid Build Coastguard Worker #include "db/write_batch_internal.h"
10*9507f98cSAndroid Build Coastguard Worker #include "leveldb/db.h"
11*9507f98cSAndroid Build Coastguard Worker #include "leveldb/env.h"
12*9507f98cSAndroid Build Coastguard Worker #include "leveldb/write_batch.h"
13*9507f98cSAndroid Build Coastguard Worker #include "util/logging.h"
14*9507f98cSAndroid Build Coastguard Worker #include "util/testutil.h"
15*9507f98cSAndroid Build Coastguard Worker
16*9507f98cSAndroid Build Coastguard Worker namespace leveldb {
17*9507f98cSAndroid Build Coastguard Worker
18*9507f98cSAndroid Build Coastguard Worker class RecoveryTest : public testing::Test {
19*9507f98cSAndroid Build Coastguard Worker public:
RecoveryTest()20*9507f98cSAndroid Build Coastguard Worker RecoveryTest() : env_(Env::Default()), db_(nullptr) {
21*9507f98cSAndroid Build Coastguard Worker dbname_ = testing::TempDir() + "/recovery_test";
22*9507f98cSAndroid Build Coastguard Worker DestroyDB(dbname_, Options());
23*9507f98cSAndroid Build Coastguard Worker Open();
24*9507f98cSAndroid Build Coastguard Worker }
25*9507f98cSAndroid Build Coastguard Worker
~RecoveryTest()26*9507f98cSAndroid Build Coastguard Worker ~RecoveryTest() {
27*9507f98cSAndroid Build Coastguard Worker Close();
28*9507f98cSAndroid Build Coastguard Worker DestroyDB(dbname_, Options());
29*9507f98cSAndroid Build Coastguard Worker }
30*9507f98cSAndroid Build Coastguard Worker
dbfull() const31*9507f98cSAndroid Build Coastguard Worker DBImpl* dbfull() const { return reinterpret_cast<DBImpl*>(db_); }
env() const32*9507f98cSAndroid Build Coastguard Worker Env* env() const { return env_; }
33*9507f98cSAndroid Build Coastguard Worker
CanAppend()34*9507f98cSAndroid Build Coastguard Worker bool CanAppend() {
35*9507f98cSAndroid Build Coastguard Worker WritableFile* tmp;
36*9507f98cSAndroid Build Coastguard Worker Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp);
37*9507f98cSAndroid Build Coastguard Worker delete tmp;
38*9507f98cSAndroid Build Coastguard Worker if (s.IsNotSupportedError()) {
39*9507f98cSAndroid Build Coastguard Worker return false;
40*9507f98cSAndroid Build Coastguard Worker } else {
41*9507f98cSAndroid Build Coastguard Worker return true;
42*9507f98cSAndroid Build Coastguard Worker }
43*9507f98cSAndroid Build Coastguard Worker }
44*9507f98cSAndroid Build Coastguard Worker
Close()45*9507f98cSAndroid Build Coastguard Worker void Close() {
46*9507f98cSAndroid Build Coastguard Worker delete db_;
47*9507f98cSAndroid Build Coastguard Worker db_ = nullptr;
48*9507f98cSAndroid Build Coastguard Worker }
49*9507f98cSAndroid Build Coastguard Worker
OpenWithStatus(Options * options=nullptr)50*9507f98cSAndroid Build Coastguard Worker Status OpenWithStatus(Options* options = nullptr) {
51*9507f98cSAndroid Build Coastguard Worker Close();
52*9507f98cSAndroid Build Coastguard Worker Options opts;
53*9507f98cSAndroid Build Coastguard Worker if (options != nullptr) {
54*9507f98cSAndroid Build Coastguard Worker opts = *options;
55*9507f98cSAndroid Build Coastguard Worker } else {
56*9507f98cSAndroid Build Coastguard Worker opts.reuse_logs = true; // TODO(sanjay): test both ways
57*9507f98cSAndroid Build Coastguard Worker opts.create_if_missing = true;
58*9507f98cSAndroid Build Coastguard Worker }
59*9507f98cSAndroid Build Coastguard Worker if (opts.env == nullptr) {
60*9507f98cSAndroid Build Coastguard Worker opts.env = env_;
61*9507f98cSAndroid Build Coastguard Worker }
62*9507f98cSAndroid Build Coastguard Worker return DB::Open(opts, dbname_, &db_);
63*9507f98cSAndroid Build Coastguard Worker }
64*9507f98cSAndroid Build Coastguard Worker
Open(Options * options=nullptr)65*9507f98cSAndroid Build Coastguard Worker void Open(Options* options = nullptr) {
66*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(OpenWithStatus(options));
67*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
68*9507f98cSAndroid Build Coastguard Worker }
69*9507f98cSAndroid Build Coastguard Worker
Put(const std::string & k,const std::string & v)70*9507f98cSAndroid Build Coastguard Worker Status Put(const std::string& k, const std::string& v) {
71*9507f98cSAndroid Build Coastguard Worker return db_->Put(WriteOptions(), k, v);
72*9507f98cSAndroid Build Coastguard Worker }
73*9507f98cSAndroid Build Coastguard Worker
Get(const std::string & k,const Snapshot * snapshot=nullptr)74*9507f98cSAndroid Build Coastguard Worker std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
75*9507f98cSAndroid Build Coastguard Worker std::string result;
76*9507f98cSAndroid Build Coastguard Worker Status s = db_->Get(ReadOptions(), k, &result);
77*9507f98cSAndroid Build Coastguard Worker if (s.IsNotFound()) {
78*9507f98cSAndroid Build Coastguard Worker result = "NOT_FOUND";
79*9507f98cSAndroid Build Coastguard Worker } else if (!s.ok()) {
80*9507f98cSAndroid Build Coastguard Worker result = s.ToString();
81*9507f98cSAndroid Build Coastguard Worker }
82*9507f98cSAndroid Build Coastguard Worker return result;
83*9507f98cSAndroid Build Coastguard Worker }
84*9507f98cSAndroid Build Coastguard Worker
ManifestFileName()85*9507f98cSAndroid Build Coastguard Worker std::string ManifestFileName() {
86*9507f98cSAndroid Build Coastguard Worker std::string current;
87*9507f98cSAndroid Build Coastguard Worker EXPECT_LEVELDB_OK(
88*9507f98cSAndroid Build Coastguard Worker ReadFileToString(env_, CurrentFileName(dbname_), ¤t));
89*9507f98cSAndroid Build Coastguard Worker size_t len = current.size();
90*9507f98cSAndroid Build Coastguard Worker if (len > 0 && current[len - 1] == '\n') {
91*9507f98cSAndroid Build Coastguard Worker current.resize(len - 1);
92*9507f98cSAndroid Build Coastguard Worker }
93*9507f98cSAndroid Build Coastguard Worker return dbname_ + "/" + current;
94*9507f98cSAndroid Build Coastguard Worker }
95*9507f98cSAndroid Build Coastguard Worker
LogName(uint64_t number)96*9507f98cSAndroid Build Coastguard Worker std::string LogName(uint64_t number) { return LogFileName(dbname_, number); }
97*9507f98cSAndroid Build Coastguard Worker
RemoveLogFiles()98*9507f98cSAndroid Build Coastguard Worker size_t RemoveLogFiles() {
99*9507f98cSAndroid Build Coastguard Worker // Linux allows unlinking open files, but Windows does not.
100*9507f98cSAndroid Build Coastguard Worker // Closing the db allows for file deletion.
101*9507f98cSAndroid Build Coastguard Worker Close();
102*9507f98cSAndroid Build Coastguard Worker std::vector<uint64_t> logs = GetFiles(kLogFile);
103*9507f98cSAndroid Build Coastguard Worker for (size_t i = 0; i < logs.size(); i++) {
104*9507f98cSAndroid Build Coastguard Worker EXPECT_LEVELDB_OK(env_->RemoveFile(LogName(logs[i]))) << LogName(logs[i]);
105*9507f98cSAndroid Build Coastguard Worker }
106*9507f98cSAndroid Build Coastguard Worker return logs.size();
107*9507f98cSAndroid Build Coastguard Worker }
108*9507f98cSAndroid Build Coastguard Worker
RemoveManifestFile()109*9507f98cSAndroid Build Coastguard Worker void RemoveManifestFile() {
110*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(env_->RemoveFile(ManifestFileName()));
111*9507f98cSAndroid Build Coastguard Worker }
112*9507f98cSAndroid Build Coastguard Worker
FirstLogFile()113*9507f98cSAndroid Build Coastguard Worker uint64_t FirstLogFile() { return GetFiles(kLogFile)[0]; }
114*9507f98cSAndroid Build Coastguard Worker
GetFiles(FileType t)115*9507f98cSAndroid Build Coastguard Worker std::vector<uint64_t> GetFiles(FileType t) {
116*9507f98cSAndroid Build Coastguard Worker std::vector<std::string> filenames;
117*9507f98cSAndroid Build Coastguard Worker EXPECT_LEVELDB_OK(env_->GetChildren(dbname_, &filenames));
118*9507f98cSAndroid Build Coastguard Worker std::vector<uint64_t> result;
119*9507f98cSAndroid Build Coastguard Worker for (size_t i = 0; i < filenames.size(); i++) {
120*9507f98cSAndroid Build Coastguard Worker uint64_t number;
121*9507f98cSAndroid Build Coastguard Worker FileType type;
122*9507f98cSAndroid Build Coastguard Worker if (ParseFileName(filenames[i], &number, &type) && type == t) {
123*9507f98cSAndroid Build Coastguard Worker result.push_back(number);
124*9507f98cSAndroid Build Coastguard Worker }
125*9507f98cSAndroid Build Coastguard Worker }
126*9507f98cSAndroid Build Coastguard Worker return result;
127*9507f98cSAndroid Build Coastguard Worker }
128*9507f98cSAndroid Build Coastguard Worker
NumLogs()129*9507f98cSAndroid Build Coastguard Worker int NumLogs() { return GetFiles(kLogFile).size(); }
130*9507f98cSAndroid Build Coastguard Worker
NumTables()131*9507f98cSAndroid Build Coastguard Worker int NumTables() { return GetFiles(kTableFile).size(); }
132*9507f98cSAndroid Build Coastguard Worker
FileSize(const std::string & fname)133*9507f98cSAndroid Build Coastguard Worker uint64_t FileSize(const std::string& fname) {
134*9507f98cSAndroid Build Coastguard Worker uint64_t result;
135*9507f98cSAndroid Build Coastguard Worker EXPECT_LEVELDB_OK(env_->GetFileSize(fname, &result)) << fname;
136*9507f98cSAndroid Build Coastguard Worker return result;
137*9507f98cSAndroid Build Coastguard Worker }
138*9507f98cSAndroid Build Coastguard Worker
CompactMemTable()139*9507f98cSAndroid Build Coastguard Worker void CompactMemTable() { dbfull()->TEST_CompactMemTable(); }
140*9507f98cSAndroid Build Coastguard Worker
141*9507f98cSAndroid Build Coastguard Worker // Directly construct a log file that sets key to val.
MakeLogFile(uint64_t lognum,SequenceNumber seq,Slice key,Slice val)142*9507f98cSAndroid Build Coastguard Worker void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) {
143*9507f98cSAndroid Build Coastguard Worker std::string fname = LogFileName(dbname_, lognum);
144*9507f98cSAndroid Build Coastguard Worker WritableFile* file;
145*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(env_->NewWritableFile(fname, &file));
146*9507f98cSAndroid Build Coastguard Worker log::Writer writer(file);
147*9507f98cSAndroid Build Coastguard Worker WriteBatch batch;
148*9507f98cSAndroid Build Coastguard Worker batch.Put(key, val);
149*9507f98cSAndroid Build Coastguard Worker WriteBatchInternal::SetSequence(&batch, seq);
150*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch)));
151*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(file->Flush());
152*9507f98cSAndroid Build Coastguard Worker delete file;
153*9507f98cSAndroid Build Coastguard Worker }
154*9507f98cSAndroid Build Coastguard Worker
155*9507f98cSAndroid Build Coastguard Worker private:
156*9507f98cSAndroid Build Coastguard Worker std::string dbname_;
157*9507f98cSAndroid Build Coastguard Worker Env* env_;
158*9507f98cSAndroid Build Coastguard Worker DB* db_;
159*9507f98cSAndroid Build Coastguard Worker };
160*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,ManifestReused)161*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, ManifestReused) {
162*9507f98cSAndroid Build Coastguard Worker if (!CanAppend()) {
163*9507f98cSAndroid Build Coastguard Worker std::fprintf(stderr,
164*9507f98cSAndroid Build Coastguard Worker "skipping test because env does not support appending\n");
165*9507f98cSAndroid Build Coastguard Worker return;
166*9507f98cSAndroid Build Coastguard Worker }
167*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
168*9507f98cSAndroid Build Coastguard Worker Close();
169*9507f98cSAndroid Build Coastguard Worker std::string old_manifest = ManifestFileName();
170*9507f98cSAndroid Build Coastguard Worker Open();
171*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(old_manifest, ManifestFileName());
172*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
173*9507f98cSAndroid Build Coastguard Worker Open();
174*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(old_manifest, ManifestFileName());
175*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
176*9507f98cSAndroid Build Coastguard Worker }
177*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,LargeManifestCompacted)178*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, LargeManifestCompacted) {
179*9507f98cSAndroid Build Coastguard Worker if (!CanAppend()) {
180*9507f98cSAndroid Build Coastguard Worker std::fprintf(stderr,
181*9507f98cSAndroid Build Coastguard Worker "skipping test because env does not support appending\n");
182*9507f98cSAndroid Build Coastguard Worker return;
183*9507f98cSAndroid Build Coastguard Worker }
184*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
185*9507f98cSAndroid Build Coastguard Worker Close();
186*9507f98cSAndroid Build Coastguard Worker std::string old_manifest = ManifestFileName();
187*9507f98cSAndroid Build Coastguard Worker
188*9507f98cSAndroid Build Coastguard Worker // Pad with zeroes to make manifest file very big.
189*9507f98cSAndroid Build Coastguard Worker {
190*9507f98cSAndroid Build Coastguard Worker uint64_t len = FileSize(old_manifest);
191*9507f98cSAndroid Build Coastguard Worker WritableFile* file;
192*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(env()->NewAppendableFile(old_manifest, &file));
193*9507f98cSAndroid Build Coastguard Worker std::string zeroes(3 * 1048576 - static_cast<size_t>(len), 0);
194*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(file->Append(zeroes));
195*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(file->Flush());
196*9507f98cSAndroid Build Coastguard Worker delete file;
197*9507f98cSAndroid Build Coastguard Worker }
198*9507f98cSAndroid Build Coastguard Worker
199*9507f98cSAndroid Build Coastguard Worker Open();
200*9507f98cSAndroid Build Coastguard Worker std::string new_manifest = ManifestFileName();
201*9507f98cSAndroid Build Coastguard Worker ASSERT_NE(old_manifest, new_manifest);
202*9507f98cSAndroid Build Coastguard Worker ASSERT_GT(10000, FileSize(new_manifest));
203*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
204*9507f98cSAndroid Build Coastguard Worker
205*9507f98cSAndroid Build Coastguard Worker Open();
206*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(new_manifest, ManifestFileName());
207*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
208*9507f98cSAndroid Build Coastguard Worker }
209*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,NoLogFiles)210*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, NoLogFiles) {
211*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
212*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, RemoveLogFiles());
213*9507f98cSAndroid Build Coastguard Worker Open();
214*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("NOT_FOUND", Get("foo"));
215*9507f98cSAndroid Build Coastguard Worker Open();
216*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("NOT_FOUND", Get("foo"));
217*9507f98cSAndroid Build Coastguard Worker }
218*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,LogFileReuse)219*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, LogFileReuse) {
220*9507f98cSAndroid Build Coastguard Worker if (!CanAppend()) {
221*9507f98cSAndroid Build Coastguard Worker std::fprintf(stderr,
222*9507f98cSAndroid Build Coastguard Worker "skipping test because env does not support appending\n");
223*9507f98cSAndroid Build Coastguard Worker return;
224*9507f98cSAndroid Build Coastguard Worker }
225*9507f98cSAndroid Build Coastguard Worker for (int i = 0; i < 2; i++) {
226*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
227*9507f98cSAndroid Build Coastguard Worker if (i == 0) {
228*9507f98cSAndroid Build Coastguard Worker // Compact to ensure current log is empty
229*9507f98cSAndroid Build Coastguard Worker CompactMemTable();
230*9507f98cSAndroid Build Coastguard Worker }
231*9507f98cSAndroid Build Coastguard Worker Close();
232*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
233*9507f98cSAndroid Build Coastguard Worker uint64_t number = FirstLogFile();
234*9507f98cSAndroid Build Coastguard Worker if (i == 0) {
235*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(0, FileSize(LogName(number)));
236*9507f98cSAndroid Build Coastguard Worker } else {
237*9507f98cSAndroid Build Coastguard Worker ASSERT_LT(0, FileSize(LogName(number)));
238*9507f98cSAndroid Build Coastguard Worker }
239*9507f98cSAndroid Build Coastguard Worker Open();
240*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
241*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file";
242*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
243*9507f98cSAndroid Build Coastguard Worker Open();
244*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
245*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file";
246*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar", Get("foo"));
247*9507f98cSAndroid Build Coastguard Worker }
248*9507f98cSAndroid Build Coastguard Worker }
249*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,MultipleMemTables)250*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, MultipleMemTables) {
251*9507f98cSAndroid Build Coastguard Worker // Make a large log.
252*9507f98cSAndroid Build Coastguard Worker const int kNum = 1000;
253*9507f98cSAndroid Build Coastguard Worker for (int i = 0; i < kNum; i++) {
254*9507f98cSAndroid Build Coastguard Worker char buf[100];
255*9507f98cSAndroid Build Coastguard Worker std::snprintf(buf, sizeof(buf), "%050d", i);
256*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put(buf, buf));
257*9507f98cSAndroid Build Coastguard Worker }
258*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(0, NumTables());
259*9507f98cSAndroid Build Coastguard Worker Close();
260*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(0, NumTables());
261*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
262*9507f98cSAndroid Build Coastguard Worker uint64_t old_log_file = FirstLogFile();
263*9507f98cSAndroid Build Coastguard Worker
264*9507f98cSAndroid Build Coastguard Worker // Force creation of multiple memtables by reducing the write buffer size.
265*9507f98cSAndroid Build Coastguard Worker Options opt;
266*9507f98cSAndroid Build Coastguard Worker opt.reuse_logs = true;
267*9507f98cSAndroid Build Coastguard Worker opt.write_buffer_size = (kNum * 100) / 2;
268*9507f98cSAndroid Build Coastguard Worker Open(&opt);
269*9507f98cSAndroid Build Coastguard Worker ASSERT_LE(2, NumTables());
270*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
271*9507f98cSAndroid Build Coastguard Worker ASSERT_NE(old_log_file, FirstLogFile()) << "must not reuse log";
272*9507f98cSAndroid Build Coastguard Worker for (int i = 0; i < kNum; i++) {
273*9507f98cSAndroid Build Coastguard Worker char buf[100];
274*9507f98cSAndroid Build Coastguard Worker std::snprintf(buf, sizeof(buf), "%050d", i);
275*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(buf, Get(buf));
276*9507f98cSAndroid Build Coastguard Worker }
277*9507f98cSAndroid Build Coastguard Worker }
278*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,MultipleLogFiles)279*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, MultipleLogFiles) {
280*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
281*9507f98cSAndroid Build Coastguard Worker Close();
282*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
283*9507f98cSAndroid Build Coastguard Worker
284*9507f98cSAndroid Build Coastguard Worker // Make a bunch of uncompacted log files.
285*9507f98cSAndroid Build Coastguard Worker uint64_t old_log = FirstLogFile();
286*9507f98cSAndroid Build Coastguard Worker MakeLogFile(old_log + 1, 1000, "hello", "world");
287*9507f98cSAndroid Build Coastguard Worker MakeLogFile(old_log + 2, 1001, "hi", "there");
288*9507f98cSAndroid Build Coastguard Worker MakeLogFile(old_log + 3, 1002, "foo", "bar2");
289*9507f98cSAndroid Build Coastguard Worker
290*9507f98cSAndroid Build Coastguard Worker // Recover and check that all log files were processed.
291*9507f98cSAndroid Build Coastguard Worker Open();
292*9507f98cSAndroid Build Coastguard Worker ASSERT_LE(1, NumTables());
293*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
294*9507f98cSAndroid Build Coastguard Worker uint64_t new_log = FirstLogFile();
295*9507f98cSAndroid Build Coastguard Worker ASSERT_LE(old_log + 3, new_log);
296*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar2", Get("foo"));
297*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("world", Get("hello"));
298*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("there", Get("hi"));
299*9507f98cSAndroid Build Coastguard Worker
300*9507f98cSAndroid Build Coastguard Worker // Test that previous recovery produced recoverable state.
301*9507f98cSAndroid Build Coastguard Worker Open();
302*9507f98cSAndroid Build Coastguard Worker ASSERT_LE(1, NumTables());
303*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
304*9507f98cSAndroid Build Coastguard Worker if (CanAppend()) {
305*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(new_log, FirstLogFile());
306*9507f98cSAndroid Build Coastguard Worker }
307*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar2", Get("foo"));
308*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("world", Get("hello"));
309*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("there", Get("hi"));
310*9507f98cSAndroid Build Coastguard Worker
311*9507f98cSAndroid Build Coastguard Worker // Check that introducing an older log file does not cause it to be re-read.
312*9507f98cSAndroid Build Coastguard Worker Close();
313*9507f98cSAndroid Build Coastguard Worker MakeLogFile(old_log + 1, 2000, "hello", "stale write");
314*9507f98cSAndroid Build Coastguard Worker Open();
315*9507f98cSAndroid Build Coastguard Worker ASSERT_LE(1, NumTables());
316*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(1, NumLogs());
317*9507f98cSAndroid Build Coastguard Worker if (CanAppend()) {
318*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ(new_log, FirstLogFile());
319*9507f98cSAndroid Build Coastguard Worker }
320*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("bar2", Get("foo"));
321*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("world", Get("hello"));
322*9507f98cSAndroid Build Coastguard Worker ASSERT_EQ("there", Get("hi"));
323*9507f98cSAndroid Build Coastguard Worker }
324*9507f98cSAndroid Build Coastguard Worker
TEST_F(RecoveryTest,ManifestMissing)325*9507f98cSAndroid Build Coastguard Worker TEST_F(RecoveryTest, ManifestMissing) {
326*9507f98cSAndroid Build Coastguard Worker ASSERT_LEVELDB_OK(Put("foo", "bar"));
327*9507f98cSAndroid Build Coastguard Worker Close();
328*9507f98cSAndroid Build Coastguard Worker RemoveManifestFile();
329*9507f98cSAndroid Build Coastguard Worker
330*9507f98cSAndroid Build Coastguard Worker Status status = OpenWithStatus();
331*9507f98cSAndroid Build Coastguard Worker ASSERT_TRUE(status.IsCorruption());
332*9507f98cSAndroid Build Coastguard Worker }
333*9507f98cSAndroid Build Coastguard Worker
334*9507f98cSAndroid Build Coastguard Worker } // namespace leveldb
335*9507f98cSAndroid Build Coastguard Worker
336