作者: 韩晨旭 10225101440 李畅 10225102463
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
9.6 KiB

  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include "include/db.h"
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include "include/env.h"
  10. #include "include/table.h"
  11. #include "include/write_batch.h"
  12. #include "db/db_impl.h"
  13. #include "db/filename.h"
  14. #include "db/version_set.h"
  15. #include "util/logging.h"
  16. #include "util/testharness.h"
  17. #include "util/testutil.h"
  18. namespace leveldb {
  19. static const int kValueSize = 1000;
  20. class CorruptionTest {
  21. public:
  22. test::ErrorEnv env_;
  23. Random rnd_;
  24. std::string dbname_;
  25. Options options_;
  26. DB* db_;
  27. CorruptionTest() : rnd_(test::RandomSeed()) {
  28. options_.env = &env_;
  29. dbname_ = test::TmpDir() + "/db_test";
  30. DestroyDB(dbname_, options_);
  31. db_ = NULL;
  32. options_.create_if_missing = true;
  33. Reopen();
  34. options_.create_if_missing = false;
  35. }
  36. ~CorruptionTest() {
  37. delete db_;
  38. DestroyDB(dbname_, Options());
  39. }
  40. Status TryReopen(Options* options = NULL) {
  41. delete db_;
  42. db_ = NULL;
  43. Options opt = (options ? *options : options_);
  44. opt.env = &env_;
  45. return DB::Open(opt, dbname_, &db_);
  46. }
  47. void Reopen(Options* options = NULL) {
  48. ASSERT_OK(TryReopen(options));
  49. }
  50. void RepairDB() {
  51. delete db_;
  52. db_ = NULL;
  53. ASSERT_OK(::leveldb::RepairDB(dbname_, options_));
  54. }
  55. void Build(int n) {
  56. std::string key_space, value_space;
  57. WriteBatch batch;
  58. for (int i = 0; i < n; i++) {
  59. //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n);
  60. Slice key = Key(i, &key_space);
  61. batch.Clear();
  62. batch.Put(key, Value(i, &value_space));
  63. ASSERT_OK(db_->Write(WriteOptions(), &batch));
  64. }
  65. }
  66. void Check(int min_expected, int max_expected) {
  67. int next_expected = 0;
  68. int missed = 0;
  69. int bad_keys = 0;
  70. int bad_values = 0;
  71. int correct = 0;
  72. std::string value_space;
  73. Iterator* iter = db_->NewIterator(ReadOptions());
  74. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  75. uint64_t key;
  76. Slice in(iter->key());
  77. if (!ConsumeDecimalNumber(&in, &key) ||
  78. !in.empty() ||
  79. key < next_expected) {
  80. bad_keys++;
  81. continue;
  82. }
  83. missed += (key - next_expected);
  84. next_expected = key + 1;
  85. if (iter->value() != Value(key, &value_space)) {
  86. bad_values++;
  87. } else {
  88. correct++;
  89. }
  90. }
  91. delete iter;
  92. fprintf(stderr,
  93. "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n",
  94. min_expected, max_expected, correct, bad_keys, bad_values, missed);
  95. ASSERT_LE(min_expected, correct);
  96. ASSERT_GE(max_expected, correct);
  97. }
  98. void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
  99. // Pick file to corrupt
  100. std::vector<std::string> filenames;
  101. ASSERT_OK(env_.GetChildren(dbname_, &filenames));
  102. uint64_t number;
  103. LargeValueRef large_ref;
  104. FileType type;
  105. std::vector<std::string> candidates;
  106. for (int i = 0; i < filenames.size(); i++) {
  107. if (ParseFileName(filenames[i], &number, &large_ref, &type) &&
  108. type == filetype) {
  109. candidates.push_back(dbname_ + "/" + filenames[i]);
  110. }
  111. }
  112. ASSERT_TRUE(!candidates.empty()) << filetype;
  113. std::string fname = candidates[rnd_.Uniform(candidates.size())];
  114. struct stat sbuf;
  115. if (stat(fname.c_str(), &sbuf) != 0) {
  116. const char* msg = strerror(errno);
  117. ASSERT_TRUE(false) << fname << ": " << msg;
  118. }
  119. if (offset < 0) {
  120. // Relative to end of file; make it absolute
  121. if (-offset > sbuf.st_size) {
  122. offset = 0;
  123. } else {
  124. offset = sbuf.st_size + offset;
  125. }
  126. }
  127. if (offset > sbuf.st_size) {
  128. offset = sbuf.st_size;
  129. }
  130. if (offset + bytes_to_corrupt > sbuf.st_size) {
  131. bytes_to_corrupt = sbuf.st_size - offset;
  132. }
  133. // Do it
  134. std::string contents;
  135. Status s = ReadFileToString(Env::Default(), fname, &contents);
  136. ASSERT_TRUE(s.ok()) << s.ToString();
  137. for (int i = 0; i < bytes_to_corrupt; i++) {
  138. contents[i + offset] ^= 0x80;
  139. }
  140. s = WriteStringToFile(Env::Default(), contents, fname);
  141. ASSERT_TRUE(s.ok()) << s.ToString();
  142. }
  143. uint64_t Property(const std::string& name) {
  144. uint64_t result;
  145. if (!db_->GetProperty(name, &result)) {
  146. result = ~static_cast<uint64_t>(0);
  147. }
  148. return result;
  149. }
  150. // Return the ith key
  151. Slice Key(int i, std::string* storage) {
  152. char buf[100];
  153. snprintf(buf, sizeof(buf), "%016d", i);
  154. storage->assign(buf, strlen(buf));
  155. return Slice(*storage);
  156. }
  157. // Return the value to associate with the specified key
  158. Slice Value(int k, std::string* storage) {
  159. Random r(k);
  160. return test::RandomString(&r, kValueSize, storage);
  161. }
  162. };
  163. TEST(CorruptionTest, Recovery) {
  164. Build(10);
  165. Check(10, 10);
  166. Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record
  167. Corrupt(kLogFile, 2*kValueSize, 1); // Somewhere in second log record?
  168. Reopen();
  169. Check(8, 8);
  170. }
  171. TEST(CorruptionTest, RecoverWriteError) {
  172. env_.writable_file_error_ = true;
  173. Status s = TryReopen();
  174. ASSERT_TRUE(!s.ok());
  175. }
  176. TEST(CorruptionTest, NewFileErrorDuringWrite) {
  177. // Do enough writing to force minor compaction
  178. env_.writable_file_error_ = true;
  179. const int num = 3 + (Options().write_buffer_size / kValueSize);
  180. std::string value_storage;
  181. Status s;
  182. for (int i = 0; s.ok() && i < num; i++) {
  183. WriteBatch batch;
  184. batch.Put("a", Value(100, &value_storage));
  185. s = db_->Write(WriteOptions(), &batch);
  186. }
  187. ASSERT_TRUE(!s.ok());
  188. ASSERT_GE(env_.num_writable_file_errors_, 1);
  189. env_.writable_file_error_ = false;
  190. Reopen();
  191. }
  192. TEST(CorruptionTest, TableFile) {
  193. Build(100);
  194. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  195. dbi->TEST_CompactMemTable();
  196. dbi->TEST_CompactRange(0, "", "~");
  197. dbi->TEST_CompactRange(1, "", "~");
  198. Corrupt(kTableFile, 100, 1);
  199. Check(99, 99);
  200. }
  201. TEST(CorruptionTest, TableFileIndexData) {
  202. Build(10000); // Enough to build multiple Tables
  203. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  204. dbi->TEST_CompactMemTable();
  205. dbi->TEST_CompactRange(0, "", "~");
  206. dbi->TEST_CompactRange(1, "", "~");
  207. Corrupt(kTableFile, -1000, 500);
  208. Reopen();
  209. Check(5000, 9999);
  210. }
  211. TEST(CorruptionTest, MissingDescriptor) {
  212. Build(1000);
  213. RepairDB();
  214. Reopen();
  215. Check(1000, 1000);
  216. }
  217. TEST(CorruptionTest, SequenceNumberRecovery) {
  218. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
  219. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
  220. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3"));
  221. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4"));
  222. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5"));
  223. RepairDB();
  224. Reopen();
  225. std::string v;
  226. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  227. ASSERT_EQ("v5", v);
  228. // Write something. If sequence number was not recovered properly,
  229. // it will be hidden by an earlier write.
  230. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6"));
  231. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  232. ASSERT_EQ("v6", v);
  233. Reopen();
  234. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  235. ASSERT_EQ("v6", v);
  236. }
  237. TEST(CorruptionTest, LargeValueRecovery) {
  238. Options options;
  239. options.large_value_threshold = 10000;
  240. Reopen(&options);
  241. Random rnd(301);
  242. std::string big;
  243. ASSERT_OK(db_->Put(WriteOptions(),
  244. "foo", test::RandomString(&rnd, 100000, &big)));
  245. std::string v;
  246. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  247. ASSERT_EQ(big, v);
  248. RepairDB();
  249. Reopen();
  250. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  251. ASSERT_EQ(big, v);
  252. Reopen();
  253. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  254. ASSERT_EQ(big, v);
  255. }
  256. TEST(CorruptionTest, CorruptedDescriptor) {
  257. ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello"));
  258. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  259. dbi->TEST_CompactMemTable();
  260. dbi->TEST_CompactRange(0, "", "~");
  261. Corrupt(kDescriptorFile, 0, 1000);
  262. Status s = TryReopen();
  263. ASSERT_TRUE(!s.ok());
  264. RepairDB();
  265. Reopen();
  266. std::string v;
  267. ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
  268. ASSERT_EQ("hello", v);
  269. }
  270. TEST(CorruptionTest, CompactionInputError) {
  271. Build(10);
  272. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  273. dbi->TEST_CompactMemTable();
  274. ASSERT_EQ(1, Property("leveldb.num-files-at-level0"));
  275. Corrupt(kTableFile, 100, 1);
  276. Check(9, 9);
  277. // Force compactions by writing lots of values
  278. Build(10000);
  279. Check(10000, 10000);
  280. dbi->TEST_CompactRange(0, "", "~");
  281. ASSERT_EQ(0, Property("leveldb.num-files-at-level0"));
  282. }
  283. TEST(CorruptionTest, CompactionInputErrorParanoid) {
  284. Options options;
  285. options.paranoid_checks = true;
  286. Reopen(&options);
  287. Build(10);
  288. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  289. dbi->TEST_CompactMemTable();
  290. ASSERT_EQ(1, Property("leveldb.num-files-at-level0"));
  291. Corrupt(kTableFile, 100, 1);
  292. Check(9, 9);
  293. // Write must eventually fail because of corrupted table
  294. Status s;
  295. std::string tmp1, tmp2;
  296. for (int i = 0; i < 10000 && s.ok(); i++) {
  297. s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2));
  298. }
  299. ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";
  300. }
  301. TEST(CorruptionTest, UnrelatedKeys) {
  302. Build(10);
  303. DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
  304. dbi->TEST_CompactMemTable();
  305. Corrupt(kTableFile, 100, 1);
  306. std::string tmp1, tmp2;
  307. ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
  308. std::string v;
  309. ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
  310. ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
  311. dbi->TEST_CompactMemTable();
  312. ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
  313. ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
  314. }
  315. }
  316. int main(int argc, char** argv) {
  317. return leveldb::test::RunAllTests();
  318. }