xref: /aosp_15_r20/external/leveldb/db/recovery_test.cc (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
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_), &current));
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