corruption_test.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #ifndef ROCKSDB_LITE
  10. #include "rocksdb/db.h"
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <cinttypes>
  16. #include "db/db_impl/db_impl.h"
  17. #include "db/db_test_util.h"
  18. #include "db/log_format.h"
  19. #include "db/version_set.h"
  20. #include "env/composite_env_wrapper.h"
  21. #include "file/filename.h"
  22. #include "rocksdb/cache.h"
  23. #include "rocksdb/convenience.h"
  24. #include "rocksdb/env.h"
  25. #include "rocksdb/table.h"
  26. #include "rocksdb/write_batch.h"
  27. #include "table/block_based/block_based_table_builder.h"
  28. #include "table/meta_blocks.h"
  29. #include "test_util/testharness.h"
  30. #include "test_util/testutil.h"
  31. #include "util/string_util.h"
  32. namespace ROCKSDB_NAMESPACE {
  33. static const int kValueSize = 1000;
  34. class CorruptionTest : public testing::Test {
  35. public:
  36. test::ErrorEnv env_;
  37. std::string dbname_;
  38. std::shared_ptr<Cache> tiny_cache_;
  39. Options options_;
  40. DB* db_;
  41. CorruptionTest() {
  42. // If LRU cache shard bit is smaller than 2 (or -1 which will automatically
  43. // set it to 0), test SequenceNumberRecovery will fail, likely because of a
  44. // bug in recovery code. Keep it 4 for now to make the test passes.
  45. tiny_cache_ = NewLRUCache(100, 4);
  46. options_.wal_recovery_mode = WALRecoveryMode::kTolerateCorruptedTailRecords;
  47. options_.env = &env_;
  48. dbname_ = test::PerThreadDBPath("corruption_test");
  49. DestroyDB(dbname_, options_);
  50. db_ = nullptr;
  51. options_.create_if_missing = true;
  52. BlockBasedTableOptions table_options;
  53. table_options.block_size_deviation = 0; // make unit test pass for now
  54. options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
  55. Reopen();
  56. options_.create_if_missing = false;
  57. }
  58. ~CorruptionTest() override {
  59. delete db_;
  60. DestroyDB(dbname_, Options());
  61. }
  62. void CloseDb() {
  63. delete db_;
  64. db_ = nullptr;
  65. }
  66. Status TryReopen(Options* options = nullptr) {
  67. delete db_;
  68. db_ = nullptr;
  69. Options opt = (options ? *options : options_);
  70. if (opt.env == Options().env) {
  71. // If env is not overridden, replace it with ErrorEnv.
  72. // Otherwise, the test already uses a non-default Env.
  73. opt.env = &env_;
  74. }
  75. opt.arena_block_size = 4096;
  76. BlockBasedTableOptions table_options;
  77. table_options.block_cache = tiny_cache_;
  78. table_options.block_size_deviation = 0;
  79. opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
  80. return DB::Open(opt, dbname_, &db_);
  81. }
  82. void Reopen(Options* options = nullptr) {
  83. ASSERT_OK(TryReopen(options));
  84. }
  85. void RepairDB() {
  86. delete db_;
  87. db_ = nullptr;
  88. ASSERT_OK(::ROCKSDB_NAMESPACE::RepairDB(dbname_, options_));
  89. }
  90. void Build(int n, int flush_every = 0) {
  91. std::string key_space, value_space;
  92. WriteBatch batch;
  93. for (int i = 0; i < n; i++) {
  94. if (flush_every != 0 && i != 0 && i % flush_every == 0) {
  95. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  96. dbi->TEST_FlushMemTable();
  97. }
  98. //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n);
  99. Slice key = Key(i, &key_space);
  100. batch.Clear();
  101. batch.Put(key, Value(i, &value_space));
  102. ASSERT_OK(db_->Write(WriteOptions(), &batch));
  103. }
  104. }
  105. void Check(int min_expected, int max_expected) {
  106. uint64_t next_expected = 0;
  107. uint64_t missed = 0;
  108. int bad_keys = 0;
  109. int bad_values = 0;
  110. int correct = 0;
  111. std::string value_space;
  112. // Do not verify checksums. If we verify checksums then the
  113. // db itself will raise errors because data is corrupted.
  114. // Instead, we want the reads to be successful and this test
  115. // will detect whether the appropriate corruptions have
  116. // occurred.
  117. Iterator* iter = db_->NewIterator(ReadOptions(false, true));
  118. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  119. uint64_t key;
  120. Slice in(iter->key());
  121. if (!ConsumeDecimalNumber(&in, &key) ||
  122. !in.empty() ||
  123. key < next_expected) {
  124. bad_keys++;
  125. continue;
  126. }
  127. missed += (key - next_expected);
  128. next_expected = key + 1;
  129. if (iter->value() != Value(static_cast<int>(key), &value_space)) {
  130. bad_values++;
  131. } else {
  132. correct++;
  133. }
  134. }
  135. delete iter;
  136. fprintf(stderr,
  137. "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%llu\n",
  138. min_expected, max_expected, correct, bad_keys, bad_values,
  139. static_cast<unsigned long long>(missed));
  140. ASSERT_LE(min_expected, correct);
  141. ASSERT_GE(max_expected, correct);
  142. }
  143. void CorruptFile(const std::string& fname, int offset, int bytes_to_corrupt) {
  144. struct stat sbuf;
  145. if (stat(fname.c_str(), &sbuf) != 0) {
  146. const char* msg = strerror(errno);
  147. FAIL() << fname << ": " << msg;
  148. }
  149. if (offset < 0) {
  150. // Relative to end of file; make it absolute
  151. if (-offset > sbuf.st_size) {
  152. offset = 0;
  153. } else {
  154. offset = static_cast<int>(sbuf.st_size + offset);
  155. }
  156. }
  157. if (offset > sbuf.st_size) {
  158. offset = static_cast<int>(sbuf.st_size);
  159. }
  160. if (offset + bytes_to_corrupt > sbuf.st_size) {
  161. bytes_to_corrupt = static_cast<int>(sbuf.st_size - offset);
  162. }
  163. // Do it
  164. std::string contents;
  165. Status s = ReadFileToString(Env::Default(), fname, &contents);
  166. ASSERT_TRUE(s.ok()) << s.ToString();
  167. for (int i = 0; i < bytes_to_corrupt; i++) {
  168. contents[i + offset] ^= 0x80;
  169. }
  170. s = WriteStringToFile(Env::Default(), contents, fname);
  171. ASSERT_TRUE(s.ok()) << s.ToString();
  172. Options options;
  173. EnvOptions env_options;
  174. options.file_system.reset(new LegacyFileSystemWrapper(options.env));
  175. ASSERT_NOK(VerifySstFileChecksum(options, env_options, fname));
  176. }
  177. void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
  178. // Pick file to corrupt
  179. std::vector<std::string> filenames;
  180. ASSERT_OK(env_.GetChildren(dbname_, &filenames));
  181. uint64_t number;
  182. FileType type;
  183. std::string fname;
  184. int picked_number = -1;
  185. for (size_t i = 0; i < filenames.size(); i++) {
  186. if (ParseFileName(filenames[i], &number, &type) &&
  187. type == filetype &&
  188. static_cast<int>(number) > picked_number) { // Pick latest file
  189. fname = dbname_ + "/" + filenames[i];
  190. picked_number = static_cast<int>(number);
  191. }
  192. }
  193. ASSERT_TRUE(!fname.empty()) << filetype;
  194. CorruptFile(fname, offset, bytes_to_corrupt);
  195. }
  196. // corrupts exactly one file at level `level`. if no file found at level,
  197. // asserts
  198. void CorruptTableFileAtLevel(int level, int offset, int bytes_to_corrupt) {
  199. std::vector<LiveFileMetaData> metadata;
  200. db_->GetLiveFilesMetaData(&metadata);
  201. for (const auto& m : metadata) {
  202. if (m.level == level) {
  203. CorruptFile(dbname_ + "/" + m.name, offset, bytes_to_corrupt);
  204. return;
  205. }
  206. }
  207. FAIL() << "no file found at level";
  208. }
  209. int Property(const std::string& name) {
  210. std::string property;
  211. int result;
  212. if (db_->GetProperty(name, &property) &&
  213. sscanf(property.c_str(), "%d", &result) == 1) {
  214. return result;
  215. } else {
  216. return -1;
  217. }
  218. }
  219. // Return the ith key
  220. Slice Key(int i, std::string* storage) {
  221. char buf[100];
  222. snprintf(buf, sizeof(buf), "%016d", i);
  223. storage->assign(buf, strlen(buf));
  224. return Slice(*storage);
  225. }
  226. // Return the value to associate with the specified key
  227. Slice Value(int k, std::string* storage) {
  228. if (k == 0) {
  229. // Ugh. Random seed of 0 used to produce no entropy. This code
  230. // preserves the implementation that was in place when all of the
  231. // magic values in this file were picked.
  232. *storage = std::string(kValueSize, ' ');
  233. return Slice(*storage);
  234. } else {
  235. Random r(k);
  236. return test::RandomString(&r, kValueSize, storage);
  237. }
  238. }
  239. };
  240. TEST_F(CorruptionTest, Recovery) {
  241. Build(100);
  242. Check(100, 100);
  243. #ifdef OS_WIN
  244. // On Wndows OS Disk cache does not behave properly
  245. // We do not call FlushBuffers on every Flush. If we do not close
  246. // the log file prior to the corruption we end up with the first
  247. // block not corrupted but only the second. However, under the debugger
  248. // things work just fine but never pass when running normally
  249. // For that reason people may want to run with unbuffered I/O. That option
  250. // is not available for WAL though.
  251. CloseDb();
  252. #endif
  253. Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record
  254. Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block
  255. ASSERT_TRUE(!TryReopen().ok());
  256. options_.paranoid_checks = false;
  257. Reopen(&options_);
  258. // The 64 records in the first two log blocks are completely lost.
  259. Check(36, 36);
  260. }
  261. TEST_F(CorruptionTest, RecoverWriteError) {
  262. env_.writable_file_error_ = true;
  263. Status s = TryReopen();
  264. ASSERT_TRUE(!s.ok());
  265. }
  266. TEST_F(CorruptionTest, NewFileErrorDuringWrite) {
  267. // Do enough writing to force minor compaction
  268. env_.writable_file_error_ = true;
  269. const int num =
  270. static_cast<int>(3 + (Options().write_buffer_size / kValueSize));
  271. std::string value_storage;
  272. Status s;
  273. bool failed = false;
  274. for (int i = 0; i < num; i++) {
  275. WriteBatch batch;
  276. batch.Put("a", Value(100, &value_storage));
  277. s = db_->Write(WriteOptions(), &batch);
  278. if (!s.ok()) {
  279. failed = true;
  280. }
  281. ASSERT_TRUE(!failed || !s.ok());
  282. }
  283. ASSERT_TRUE(!s.ok());
  284. ASSERT_GE(env_.num_writable_file_errors_, 1);
  285. env_.writable_file_error_ = false;
  286. Reopen();
  287. }
  288. TEST_F(CorruptionTest, TableFile) {
  289. Build(100);
  290. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  291. dbi->TEST_FlushMemTable();
  292. dbi->TEST_CompactRange(0, nullptr, nullptr);
  293. dbi->TEST_CompactRange(1, nullptr, nullptr);
  294. Corrupt(kTableFile, 100, 1);
  295. Check(99, 99);
  296. ASSERT_NOK(dbi->VerifyChecksum());
  297. }
  298. TEST_F(CorruptionTest, VerifyChecksumReadahead) {
  299. Options options;
  300. SpecialEnv senv(Env::Default());
  301. options.env = &senv;
  302. // Disable block cache as we are going to check checksum for
  303. // the same file twice and measure number of reads.
  304. BlockBasedTableOptions table_options_no_bc;
  305. table_options_no_bc.no_block_cache = true;
  306. options.table_factory.reset(NewBlockBasedTableFactory(table_options_no_bc));
  307. Reopen(&options);
  308. Build(10000);
  309. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  310. dbi->TEST_FlushMemTable();
  311. dbi->TEST_CompactRange(0, nullptr, nullptr);
  312. dbi->TEST_CompactRange(1, nullptr, nullptr);
  313. senv.count_random_reads_ = true;
  314. senv.random_read_counter_.Reset();
  315. ASSERT_OK(dbi->VerifyChecksum());
  316. // Make sure the counter is enabled.
  317. ASSERT_GT(senv.random_read_counter_.Read(), 0);
  318. // The SST file is about 10MB. Default readahead size is 256KB.
  319. // Give a conservative 20 reads for metadata blocks, The number
  320. // of random reads should be within 10 MB / 256KB + 20 = 60.
  321. ASSERT_LT(senv.random_read_counter_.Read(), 60);
  322. senv.random_read_bytes_counter_ = 0;
  323. ReadOptions ro;
  324. ro.readahead_size = size_t{32 * 1024};
  325. ASSERT_OK(dbi->VerifyChecksum(ro));
  326. // The SST file is about 10MB. We set readahead size to 32KB.
  327. // Give 0 to 20 reads for metadata blocks, and allow real read
  328. // to range from 24KB to 48KB. The lower bound would be:
  329. // 10MB / 48KB + 0 = 213
  330. // The higher bound is
  331. // 10MB / 24KB + 20 = 447.
  332. ASSERT_GE(senv.random_read_counter_.Read(), 213);
  333. ASSERT_LE(senv.random_read_counter_.Read(), 447);
  334. // Test readahead shouldn't break mmap mode (where it should be
  335. // disabled).
  336. options.allow_mmap_reads = true;
  337. Reopen(&options);
  338. dbi = static_cast<DBImpl*>(db_);
  339. ASSERT_OK(dbi->VerifyChecksum(ro));
  340. CloseDb();
  341. }
  342. TEST_F(CorruptionTest, TableFileIndexData) {
  343. Options options;
  344. // very big, we'll trigger flushes manually
  345. options.write_buffer_size = 100 * 1024 * 1024;
  346. Reopen(&options);
  347. // build 2 tables, flush at 5000
  348. Build(10000, 5000);
  349. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  350. dbi->TEST_FlushMemTable();
  351. // corrupt an index block of an entire file
  352. Corrupt(kTableFile, -2000, 500);
  353. options.paranoid_checks = false;
  354. Reopen(&options);
  355. dbi = reinterpret_cast<DBImpl*>(db_);
  356. // one full file may be readable, since only one was corrupted
  357. // the other file should be fully non-readable, since index was corrupted
  358. Check(0, 5000);
  359. ASSERT_NOK(dbi->VerifyChecksum());
  360. // In paranoid mode, the db cannot be opened due to the corrupted file.
  361. ASSERT_TRUE(TryReopen().IsCorruption());
  362. }
  363. TEST_F(CorruptionTest, MissingDescriptor) {
  364. Build(1000);
  365. RepairDB();
  366. Reopen();
  367. Check(1000, 1000);
  368. }
  369. TEST_F(CorruptionTest, SequenceNumberRecovery) {
  370. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
  371. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
  372. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3"));
  373. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4"));
  374. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5"));
  375. RepairDB();
  376. Reopen();
  377. std::string v;
  378. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  379. ASSERT_EQ("v5", v);
  380. // Write something. If sequence number was not recovered properly,
  381. // it will be hidden by an earlier write.
  382. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6"));
  383. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  384. ASSERT_EQ("v6", v);
  385. Reopen();
  386. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  387. ASSERT_EQ("v6", v);
  388. }
  389. TEST_F(CorruptionTest, CorruptedDescriptor) {
  390. ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello"));
  391. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  392. dbi->TEST_FlushMemTable();
  393. dbi->TEST_CompactRange(0, nullptr, nullptr);
  394. Corrupt(kDescriptorFile, 0, 1000);
  395. Status s = TryReopen();
  396. ASSERT_TRUE(!s.ok());
  397. RepairDB();
  398. Reopen();
  399. std::string v;
  400. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  401. ASSERT_EQ("hello", v);
  402. }
  403. TEST_F(CorruptionTest, CompactionInputError) {
  404. Options options;
  405. Reopen(&options);
  406. Build(10);
  407. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  408. dbi->TEST_FlushMemTable();
  409. dbi->TEST_CompactRange(0, nullptr, nullptr);
  410. dbi->TEST_CompactRange(1, nullptr, nullptr);
  411. ASSERT_EQ(1, Property("rocksdb.num-files-at-level2"));
  412. Corrupt(kTableFile, 100, 1);
  413. Check(9, 9);
  414. ASSERT_NOK(dbi->VerifyChecksum());
  415. // Force compactions by writing lots of values
  416. Build(10000);
  417. Check(10000, 10000);
  418. ASSERT_NOK(dbi->VerifyChecksum());
  419. }
  420. TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
  421. Options options;
  422. options.paranoid_checks = true;
  423. options.write_buffer_size = 131072;
  424. options.max_write_buffer_number = 2;
  425. Reopen(&options);
  426. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  427. // Fill levels >= 1
  428. for (int level = 1; level < dbi->NumberLevels(); level++) {
  429. dbi->Put(WriteOptions(), "", "begin");
  430. dbi->Put(WriteOptions(), "~", "end");
  431. dbi->TEST_FlushMemTable();
  432. for (int comp_level = 0; comp_level < dbi->NumberLevels() - level;
  433. ++comp_level) {
  434. dbi->TEST_CompactRange(comp_level, nullptr, nullptr);
  435. }
  436. }
  437. Reopen(&options);
  438. dbi = reinterpret_cast<DBImpl*>(db_);
  439. Build(10);
  440. dbi->TEST_FlushMemTable();
  441. dbi->TEST_WaitForCompact();
  442. ASSERT_EQ(1, Property("rocksdb.num-files-at-level0"));
  443. CorruptTableFileAtLevel(0, 100, 1);
  444. Check(9, 9);
  445. ASSERT_NOK(dbi->VerifyChecksum());
  446. // Write must eventually fail because of corrupted table
  447. Status s;
  448. std::string tmp1, tmp2;
  449. bool failed = false;
  450. for (int i = 0; i < 10000; i++) {
  451. s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2));
  452. if (!s.ok()) {
  453. failed = true;
  454. }
  455. // if one write failed, every subsequent write must fail, too
  456. ASSERT_TRUE(!failed || !s.ok()) << "write did not fail in a corrupted db";
  457. }
  458. ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";
  459. }
  460. TEST_F(CorruptionTest, UnrelatedKeys) {
  461. Build(10);
  462. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  463. dbi->TEST_FlushMemTable();
  464. Corrupt(kTableFile, 100, 1);
  465. ASSERT_NOK(dbi->VerifyChecksum());
  466. std::string tmp1, tmp2;
  467. ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
  468. std::string v;
  469. ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
  470. ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
  471. dbi->TEST_FlushMemTable();
  472. ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
  473. ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
  474. }
  475. TEST_F(CorruptionTest, RangeDeletionCorrupted) {
  476. ASSERT_OK(
  477. db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "b"));
  478. ASSERT_OK(db_->Flush(FlushOptions()));
  479. std::vector<LiveFileMetaData> metadata;
  480. db_->GetLiveFilesMetaData(&metadata);
  481. ASSERT_EQ(static_cast<size_t>(1), metadata.size());
  482. std::string filename = dbname_ + metadata[0].name;
  483. std::unique_ptr<RandomAccessFile> file;
  484. ASSERT_OK(options_.env->NewRandomAccessFile(filename, &file, EnvOptions()));
  485. std::unique_ptr<RandomAccessFileReader> file_reader(
  486. new RandomAccessFileReader(NewLegacyRandomAccessFileWrapper(file),
  487. filename));
  488. uint64_t file_size;
  489. ASSERT_OK(options_.env->GetFileSize(filename, &file_size));
  490. BlockHandle range_del_handle;
  491. ASSERT_OK(FindMetaBlock(
  492. file_reader.get(), file_size, kBlockBasedTableMagicNumber,
  493. ImmutableCFOptions(options_), kRangeDelBlock, &range_del_handle));
  494. ASSERT_OK(TryReopen());
  495. CorruptFile(filename, static_cast<int>(range_del_handle.offset()), 1);
  496. ASSERT_TRUE(TryReopen().IsCorruption());
  497. }
  498. TEST_F(CorruptionTest, FileSystemStateCorrupted) {
  499. for (int iter = 0; iter < 2; ++iter) {
  500. Options options;
  501. options.paranoid_checks = true;
  502. options.create_if_missing = true;
  503. Reopen(&options);
  504. Build(10);
  505. ASSERT_OK(db_->Flush(FlushOptions()));
  506. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  507. std::vector<LiveFileMetaData> metadata;
  508. dbi->GetLiveFilesMetaData(&metadata);
  509. ASSERT_GT(metadata.size(), size_t(0));
  510. std::string filename = dbname_ + metadata[0].name;
  511. delete db_;
  512. db_ = nullptr;
  513. if (iter == 0) { // corrupt file size
  514. std::unique_ptr<WritableFile> file;
  515. env_.NewWritableFile(filename, &file, EnvOptions());
  516. file->Append(Slice("corrupted sst"));
  517. file.reset();
  518. Status x = TryReopen(&options);
  519. ASSERT_TRUE(x.IsCorruption());
  520. } else { // delete the file
  521. env_.DeleteFile(filename);
  522. Status x = TryReopen(&options);
  523. ASSERT_TRUE(x.IsPathNotFound());
  524. }
  525. DestroyDB(dbname_, options_);
  526. }
  527. }
  528. } // namespace ROCKSDB_NAMESPACE
  529. int main(int argc, char** argv) {
  530. ::testing::InitGoogleTest(&argc, argv);
  531. return RUN_ALL_TESTS();
  532. }
  533. #else
  534. #include <stdio.h>
  535. int main(int /*argc*/, char** /*argv*/) {
  536. fprintf(stderr, "SKIPPED as RepairDB() is not supported in ROCKSDB_LITE\n");
  537. return 0;
  538. }
  539. #endif // !ROCKSDB_LITE