提供基本的ttl测试用例
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

2128 rindas
61 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 "leveldb/db.h"
  5. #include "leveldb/filter_policy.h"
  6. #include "db/db_impl.h"
  7. #include "db/filename.h"
  8. #include "db/version_set.h"
  9. #include "db/write_batch_internal.h"
  10. #include "leveldb/cache.h"
  11. #include "leveldb/env.h"
  12. #include "leveldb/table.h"
  13. #include "util/hash.h"
  14. #include "util/logging.h"
  15. #include "util/mutexlock.h"
  16. #include "util/testharness.h"
  17. #include "util/testutil.h"
  18. namespace leveldb {
  19. static std::string RandomString(Random* rnd, int len) {
  20. std::string r;
  21. test::RandomString(rnd, len, &r);
  22. return r;
  23. }
  24. namespace {
  25. class AtomicCounter {
  26. private:
  27. port::Mutex mu_;
  28. int count_;
  29. public:
  30. AtomicCounter() : count_(0) { }
  31. void Increment() {
  32. IncrementBy(1);
  33. }
  34. void IncrementBy(int count) {
  35. MutexLock l(&mu_);
  36. count_ += count;
  37. }
  38. int Read() {
  39. MutexLock l(&mu_);
  40. return count_;
  41. }
  42. void Reset() {
  43. MutexLock l(&mu_);
  44. count_ = 0;
  45. }
  46. };
  47. void DelayMilliseconds(int millis) {
  48. Env::Default()->SleepForMicroseconds(millis * 1000);
  49. }
  50. }
  51. // Special Env used to delay background operations
  52. class SpecialEnv : public EnvWrapper {
  53. public:
  54. // sstable/log Sync() calls are blocked while this pointer is non-NULL.
  55. port::AtomicPointer delay_data_sync_;
  56. // sstable/log Sync() calls return an error.
  57. port::AtomicPointer data_sync_error_;
  58. // Simulate no-space errors while this pointer is non-NULL.
  59. port::AtomicPointer no_space_;
  60. // Simulate non-writable file system while this pointer is non-NULL
  61. port::AtomicPointer non_writable_;
  62. // Force sync of manifest files to fail while this pointer is non-NULL
  63. port::AtomicPointer manifest_sync_error_;
  64. // Force write to manifest files to fail while this pointer is non-NULL
  65. port::AtomicPointer manifest_write_error_;
  66. bool count_random_reads_;
  67. AtomicCounter random_read_counter_;
  68. explicit SpecialEnv(Env* base) : EnvWrapper(base) {
  69. delay_data_sync_.Release_Store(NULL);
  70. data_sync_error_.Release_Store(NULL);
  71. no_space_.Release_Store(NULL);
  72. non_writable_.Release_Store(NULL);
  73. count_random_reads_ = false;
  74. manifest_sync_error_.Release_Store(NULL);
  75. manifest_write_error_.Release_Store(NULL);
  76. }
  77. Status NewWritableFile(const std::string& f, WritableFile** r) {
  78. class DataFile : public WritableFile {
  79. private:
  80. SpecialEnv* env_;
  81. WritableFile* base_;
  82. public:
  83. DataFile(SpecialEnv* env, WritableFile* base)
  84. : env_(env),
  85. base_(base) {
  86. }
  87. ~DataFile() { delete base_; }
  88. Status Append(const Slice& data) {
  89. if (env_->no_space_.Acquire_Load() != NULL) {
  90. // Drop writes on the floor
  91. return Status::OK();
  92. } else {
  93. return base_->Append(data);
  94. }
  95. }
  96. Status Close() { return base_->Close(); }
  97. Status Flush() { return base_->Flush(); }
  98. Status Sync() {
  99. if (env_->data_sync_error_.Acquire_Load() != NULL) {
  100. return Status::IOError("simulated data sync error");
  101. }
  102. while (env_->delay_data_sync_.Acquire_Load() != NULL) {
  103. DelayMilliseconds(100);
  104. }
  105. return base_->Sync();
  106. }
  107. };
  108. class ManifestFile : public WritableFile {
  109. private:
  110. SpecialEnv* env_;
  111. WritableFile* base_;
  112. public:
  113. ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { }
  114. ~ManifestFile() { delete base_; }
  115. Status Append(const Slice& data) {
  116. if (env_->manifest_write_error_.Acquire_Load() != NULL) {
  117. return Status::IOError("simulated writer error");
  118. } else {
  119. return base_->Append(data);
  120. }
  121. }
  122. Status Close() { return base_->Close(); }
  123. Status Flush() { return base_->Flush(); }
  124. Status Sync() {
  125. if (env_->manifest_sync_error_.Acquire_Load() != NULL) {
  126. return Status::IOError("simulated sync error");
  127. } else {
  128. return base_->Sync();
  129. }
  130. }
  131. };
  132. if (non_writable_.Acquire_Load() != NULL) {
  133. return Status::IOError("simulated write error");
  134. }
  135. Status s = target()->NewWritableFile(f, r);
  136. if (s.ok()) {
  137. if (strstr(f.c_str(), ".ldb") != NULL ||
  138. strstr(f.c_str(), ".log") != NULL) {
  139. *r = new DataFile(this, *r);
  140. } else if (strstr(f.c_str(), "MANIFEST") != NULL) {
  141. *r = new ManifestFile(this, *r);
  142. }
  143. }
  144. return s;
  145. }
  146. Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) {
  147. class CountingFile : public RandomAccessFile {
  148. private:
  149. RandomAccessFile* target_;
  150. AtomicCounter* counter_;
  151. public:
  152. CountingFile(RandomAccessFile* target, AtomicCounter* counter)
  153. : target_(target), counter_(counter) {
  154. }
  155. virtual ~CountingFile() { delete target_; }
  156. virtual Status Read(uint64_t offset, size_t n, Slice* result,
  157. char* scratch) const {
  158. counter_->Increment();
  159. return target_->Read(offset, n, result, scratch);
  160. }
  161. };
  162. Status s = target()->NewRandomAccessFile(f, r);
  163. if (s.ok() && count_random_reads_) {
  164. *r = new CountingFile(*r, &random_read_counter_);
  165. }
  166. return s;
  167. }
  168. };
  169. class DBTest {
  170. private:
  171. const FilterPolicy* filter_policy_;
  172. // Sequence of option configurations to try
  173. enum OptionConfig {
  174. kDefault,
  175. kFilter,
  176. kUncompressed,
  177. kEnd
  178. };
  179. int option_config_;
  180. public:
  181. std::string dbname_;
  182. SpecialEnv* env_;
  183. DB* db_;
  184. Options last_options_;
  185. DBTest() : option_config_(kDefault),
  186. env_(new SpecialEnv(Env::Default())) {
  187. filter_policy_ = NewBloomFilterPolicy(10);
  188. dbname_ = test::TmpDir() + "/db_test";
  189. DestroyDB(dbname_, Options());
  190. db_ = NULL;
  191. Reopen();
  192. }
  193. ~DBTest() {
  194. delete db_;
  195. DestroyDB(dbname_, Options());
  196. delete env_;
  197. delete filter_policy_;
  198. }
  199. // Switch to a fresh database with the next option configuration to
  200. // test. Return false if there are no more configurations to test.
  201. bool ChangeOptions() {
  202. option_config_++;
  203. if (option_config_ >= kEnd) {
  204. return false;
  205. } else {
  206. DestroyAndReopen();
  207. return true;
  208. }
  209. }
  210. // Return the current option configuration.
  211. Options CurrentOptions() {
  212. Options options;
  213. switch (option_config_) {
  214. case kFilter:
  215. options.filter_policy = filter_policy_;
  216. break;
  217. case kUncompressed:
  218. options.compression = kNoCompression;
  219. break;
  220. default:
  221. break;
  222. }
  223. return options;
  224. }
  225. DBImpl* dbfull() {
  226. return reinterpret_cast<DBImpl*>(db_);
  227. }
  228. void Reopen(Options* options = NULL) {
  229. ASSERT_OK(TryReopen(options));
  230. }
  231. void Close() {
  232. delete db_;
  233. db_ = NULL;
  234. }
  235. void DestroyAndReopen(Options* options = NULL) {
  236. delete db_;
  237. db_ = NULL;
  238. DestroyDB(dbname_, Options());
  239. ASSERT_OK(TryReopen(options));
  240. }
  241. Status TryReopen(Options* options) {
  242. delete db_;
  243. db_ = NULL;
  244. Options opts;
  245. if (options != NULL) {
  246. opts = *options;
  247. } else {
  248. opts = CurrentOptions();
  249. opts.create_if_missing = true;
  250. }
  251. last_options_ = opts;
  252. return DB::Open(opts, dbname_, &db_);
  253. }
  254. Status Put(const std::string& k, const std::string& v) {
  255. return db_->Put(WriteOptions(), k, v);
  256. }
  257. Status Delete(const std::string& k) {
  258. return db_->Delete(WriteOptions(), k);
  259. }
  260. std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {
  261. ReadOptions options;
  262. options.snapshot = snapshot;
  263. std::string result;
  264. Status s = db_->Get(options, k, &result);
  265. if (s.IsNotFound()) {
  266. result = "NOT_FOUND";
  267. } else if (!s.ok()) {
  268. result = s.ToString();
  269. }
  270. return result;
  271. }
  272. // Return a string that contains all key,value pairs in order,
  273. // formatted like "(k1->v1)(k2->v2)".
  274. std::string Contents() {
  275. std::vector<std::string> forward;
  276. std::string result;
  277. Iterator* iter = db_->NewIterator(ReadOptions());
  278. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  279. std::string s = IterStatus(iter);
  280. result.push_back('(');
  281. result.append(s);
  282. result.push_back(')');
  283. forward.push_back(s);
  284. }
  285. // Check reverse iteration results are the reverse of forward results
  286. size_t matched = 0;
  287. for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
  288. ASSERT_LT(matched, forward.size());
  289. ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);
  290. matched++;
  291. }
  292. ASSERT_EQ(matched, forward.size());
  293. delete iter;
  294. return result;
  295. }
  296. std::string AllEntriesFor(const Slice& user_key) {
  297. Iterator* iter = dbfull()->TEST_NewInternalIterator();
  298. InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);
  299. iter->Seek(target.Encode());
  300. std::string result;
  301. if (!iter->status().ok()) {
  302. result = iter->status().ToString();
  303. } else {
  304. result = "[ ";
  305. bool first = true;
  306. while (iter->Valid()) {
  307. ParsedInternalKey ikey;
  308. if (!ParseInternalKey(iter->key(), &ikey)) {
  309. result += "CORRUPTED";
  310. } else {
  311. if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) {
  312. break;
  313. }
  314. if (!first) {
  315. result += ", ";
  316. }
  317. first = false;
  318. switch (ikey.type) {
  319. case kTypeValue:
  320. result += iter->value().ToString();
  321. break;
  322. case kTypeDeletion:
  323. result += "DEL";
  324. break;
  325. }
  326. }
  327. iter->Next();
  328. }
  329. if (!first) {
  330. result += " ";
  331. }
  332. result += "]";
  333. }
  334. delete iter;
  335. return result;
  336. }
  337. int NumTableFilesAtLevel(int level) {
  338. std::string property;
  339. ASSERT_TRUE(
  340. db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level),
  341. &property));
  342. return atoi(property.c_str());
  343. }
  344. int TotalTableFiles() {
  345. int result = 0;
  346. for (int level = 0; level < config::kNumLevels; level++) {
  347. result += NumTableFilesAtLevel(level);
  348. }
  349. return result;
  350. }
  351. // Return spread of files per level
  352. std::string FilesPerLevel() {
  353. std::string result;
  354. int last_non_zero_offset = 0;
  355. for (int level = 0; level < config::kNumLevels; level++) {
  356. int f = NumTableFilesAtLevel(level);
  357. char buf[100];
  358. snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
  359. result += buf;
  360. if (f > 0) {
  361. last_non_zero_offset = result.size();
  362. }
  363. }
  364. result.resize(last_non_zero_offset);
  365. return result;
  366. }
  367. int CountFiles() {
  368. std::vector<std::string> files;
  369. env_->GetChildren(dbname_, &files);
  370. return static_cast<int>(files.size());
  371. }
  372. uint64_t Size(const Slice& start, const Slice& limit) {
  373. Range r(start, limit);
  374. uint64_t size;
  375. db_->GetApproximateSizes(&r, 1, &size);
  376. return size;
  377. }
  378. void Compact(const Slice& start, const Slice& limit) {
  379. db_->CompactRange(&start, &limit);
  380. }
  381. // Do n memtable compactions, each of which produces an sstable
  382. // covering the range [small,large].
  383. void MakeTables(int n, const std::string& small, const std::string& large) {
  384. for (int i = 0; i < n; i++) {
  385. Put(small, "begin");
  386. Put(large, "end");
  387. dbfull()->TEST_CompactMemTable();
  388. }
  389. }
  390. // Prevent pushing of new sstables into deeper levels by adding
  391. // tables that cover a specified range to all levels.
  392. void FillLevels(const std::string& smallest, const std::string& largest) {
  393. MakeTables(config::kNumLevels, smallest, largest);
  394. }
  395. void DumpFileCounts(const char* label) {
  396. fprintf(stderr, "---\n%s:\n", label);
  397. fprintf(stderr, "maxoverlap: %lld\n",
  398. static_cast<long long>(
  399. dbfull()->TEST_MaxNextLevelOverlappingBytes()));
  400. for (int level = 0; level < config::kNumLevels; level++) {
  401. int num = NumTableFilesAtLevel(level);
  402. if (num > 0) {
  403. fprintf(stderr, " level %3d : %d files\n", level, num);
  404. }
  405. }
  406. }
  407. std::string DumpSSTableList() {
  408. std::string property;
  409. db_->GetProperty("leveldb.sstables", &property);
  410. return property;
  411. }
  412. std::string IterStatus(Iterator* iter) {
  413. std::string result;
  414. if (iter->Valid()) {
  415. result = iter->key().ToString() + "->" + iter->value().ToString();
  416. } else {
  417. result = "(invalid)";
  418. }
  419. return result;
  420. }
  421. bool DeleteAnSSTFile() {
  422. std::vector<std::string> filenames;
  423. ASSERT_OK(env_->GetChildren(dbname_, &filenames));
  424. uint64_t number;
  425. FileType type;
  426. for (size_t i = 0; i < filenames.size(); i++) {
  427. if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {
  428. ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number)));
  429. return true;
  430. }
  431. }
  432. return false;
  433. }
  434. // Returns number of files renamed.
  435. int RenameLDBToSST() {
  436. std::vector<std::string> filenames;
  437. ASSERT_OK(env_->GetChildren(dbname_, &filenames));
  438. uint64_t number;
  439. FileType type;
  440. int files_renamed = 0;
  441. for (size_t i = 0; i < filenames.size(); i++) {
  442. if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {
  443. const std::string from = TableFileName(dbname_, number);
  444. const std::string to = SSTTableFileName(dbname_, number);
  445. ASSERT_OK(env_->RenameFile(from, to));
  446. files_renamed++;
  447. }
  448. }
  449. return files_renamed;
  450. }
  451. };
  452. TEST(DBTest, Empty) {
  453. do {
  454. ASSERT_TRUE(db_ != NULL);
  455. ASSERT_EQ("NOT_FOUND", Get("foo"));
  456. } while (ChangeOptions());
  457. }
  458. TEST(DBTest, ReadWrite) {
  459. do {
  460. ASSERT_OK(Put("foo", "v1"));
  461. ASSERT_EQ("v1", Get("foo"));
  462. ASSERT_OK(Put("bar", "v2"));
  463. ASSERT_OK(Put("foo", "v3"));
  464. ASSERT_EQ("v3", Get("foo"));
  465. ASSERT_EQ("v2", Get("bar"));
  466. } while (ChangeOptions());
  467. }
  468. TEST(DBTest, PutDeleteGet) {
  469. do {
  470. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
  471. ASSERT_EQ("v1", Get("foo"));
  472. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
  473. ASSERT_EQ("v2", Get("foo"));
  474. ASSERT_OK(db_->Delete(WriteOptions(), "foo"));
  475. ASSERT_EQ("NOT_FOUND", Get("foo"));
  476. } while (ChangeOptions());
  477. }
  478. TEST(DBTest, GetFromImmutableLayer) {
  479. do {
  480. Options options = CurrentOptions();
  481. options.env = env_;
  482. options.write_buffer_size = 100000; // Small write buffer
  483. Reopen(&options);
  484. ASSERT_OK(Put("foo", "v1"));
  485. ASSERT_EQ("v1", Get("foo"));
  486. env_->delay_data_sync_.Release_Store(env_); // Block sync calls
  487. Put("k1", std::string(100000, 'x')); // Fill memtable
  488. Put("k2", std::string(100000, 'y')); // Trigger compaction
  489. ASSERT_EQ("v1", Get("foo"));
  490. env_->delay_data_sync_.Release_Store(NULL); // Release sync calls
  491. } while (ChangeOptions());
  492. }
  493. TEST(DBTest, GetFromVersions) {
  494. do {
  495. ASSERT_OK(Put("foo", "v1"));
  496. dbfull()->TEST_CompactMemTable();
  497. ASSERT_EQ("v1", Get("foo"));
  498. } while (ChangeOptions());
  499. }
  500. TEST(DBTest, GetSnapshot) {
  501. do {
  502. // Try with both a short key and a long key
  503. for (int i = 0; i < 2; i++) {
  504. std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
  505. ASSERT_OK(Put(key, "v1"));
  506. const Snapshot* s1 = db_->GetSnapshot();
  507. ASSERT_OK(Put(key, "v2"));
  508. ASSERT_EQ("v2", Get(key));
  509. ASSERT_EQ("v1", Get(key, s1));
  510. dbfull()->TEST_CompactMemTable();
  511. ASSERT_EQ("v2", Get(key));
  512. ASSERT_EQ("v1", Get(key, s1));
  513. db_->ReleaseSnapshot(s1);
  514. }
  515. } while (ChangeOptions());
  516. }
  517. TEST(DBTest, GetLevel0Ordering) {
  518. do {
  519. // Check that we process level-0 files in correct order. The code
  520. // below generates two level-0 files where the earlier one comes
  521. // before the later one in the level-0 file list since the earlier
  522. // one has a smaller "smallest" key.
  523. ASSERT_OK(Put("bar", "b"));
  524. ASSERT_OK(Put("foo", "v1"));
  525. dbfull()->TEST_CompactMemTable();
  526. ASSERT_OK(Put("foo", "v2"));
  527. dbfull()->TEST_CompactMemTable();
  528. ASSERT_EQ("v2", Get("foo"));
  529. } while (ChangeOptions());
  530. }
  531. TEST(DBTest, GetOrderedByLevels) {
  532. do {
  533. ASSERT_OK(Put("foo", "v1"));
  534. Compact("a", "z");
  535. ASSERT_EQ("v1", Get("foo"));
  536. ASSERT_OK(Put("foo", "v2"));
  537. ASSERT_EQ("v2", Get("foo"));
  538. dbfull()->TEST_CompactMemTable();
  539. ASSERT_EQ("v2", Get("foo"));
  540. } while (ChangeOptions());
  541. }
  542. TEST(DBTest, GetPicksCorrectFile) {
  543. do {
  544. // Arrange to have multiple files in a non-level-0 level.
  545. ASSERT_OK(Put("a", "va"));
  546. Compact("a", "b");
  547. ASSERT_OK(Put("x", "vx"));
  548. Compact("x", "y");
  549. ASSERT_OK(Put("f", "vf"));
  550. Compact("f", "g");
  551. ASSERT_EQ("va", Get("a"));
  552. ASSERT_EQ("vf", Get("f"));
  553. ASSERT_EQ("vx", Get("x"));
  554. } while (ChangeOptions());
  555. }
  556. TEST(DBTest, GetEncountersEmptyLevel) {
  557. do {
  558. // Arrange for the following to happen:
  559. // * sstable A in level 0
  560. // * nothing in level 1
  561. // * sstable B in level 2
  562. // Then do enough Get() calls to arrange for an automatic compaction
  563. // of sstable A. A bug would cause the compaction to be marked as
  564. // occuring at level 1 (instead of the correct level 0).
  565. // Step 1: First place sstables in levels 0 and 2
  566. int compaction_count = 0;
  567. while (NumTableFilesAtLevel(0) == 0 ||
  568. NumTableFilesAtLevel(2) == 0) {
  569. ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2";
  570. compaction_count++;
  571. Put("a", "begin");
  572. Put("z", "end");
  573. dbfull()->TEST_CompactMemTable();
  574. }
  575. // Step 2: clear level 1 if necessary.
  576. dbfull()->TEST_CompactRange(1, NULL, NULL);
  577. ASSERT_EQ(NumTableFilesAtLevel(0), 1);
  578. ASSERT_EQ(NumTableFilesAtLevel(1), 0);
  579. ASSERT_EQ(NumTableFilesAtLevel(2), 1);
  580. // Step 3: read a bunch of times
  581. for (int i = 0; i < 1000; i++) {
  582. ASSERT_EQ("NOT_FOUND", Get("missing"));
  583. }
  584. // Step 4: Wait for compaction to finish
  585. DelayMilliseconds(1000);
  586. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  587. } while (ChangeOptions());
  588. }
  589. TEST(DBTest, IterEmpty) {
  590. Iterator* iter = db_->NewIterator(ReadOptions());
  591. iter->SeekToFirst();
  592. ASSERT_EQ(IterStatus(iter), "(invalid)");
  593. iter->SeekToLast();
  594. ASSERT_EQ(IterStatus(iter), "(invalid)");
  595. iter->Seek("foo");
  596. ASSERT_EQ(IterStatus(iter), "(invalid)");
  597. delete iter;
  598. }
  599. TEST(DBTest, IterSingle) {
  600. ASSERT_OK(Put("a", "va"));
  601. Iterator* iter = db_->NewIterator(ReadOptions());
  602. iter->SeekToFirst();
  603. ASSERT_EQ(IterStatus(iter), "a->va");
  604. iter->Next();
  605. ASSERT_EQ(IterStatus(iter), "(invalid)");
  606. iter->SeekToFirst();
  607. ASSERT_EQ(IterStatus(iter), "a->va");
  608. iter->Prev();
  609. ASSERT_EQ(IterStatus(iter), "(invalid)");
  610. iter->SeekToLast();
  611. ASSERT_EQ(IterStatus(iter), "a->va");
  612. iter->Next();
  613. ASSERT_EQ(IterStatus(iter), "(invalid)");
  614. iter->SeekToLast();
  615. ASSERT_EQ(IterStatus(iter), "a->va");
  616. iter->Prev();
  617. ASSERT_EQ(IterStatus(iter), "(invalid)");
  618. iter->Seek("");
  619. ASSERT_EQ(IterStatus(iter), "a->va");
  620. iter->Next();
  621. ASSERT_EQ(IterStatus(iter), "(invalid)");
  622. iter->Seek("a");
  623. ASSERT_EQ(IterStatus(iter), "a->va");
  624. iter->Next();
  625. ASSERT_EQ(IterStatus(iter), "(invalid)");
  626. iter->Seek("b");
  627. ASSERT_EQ(IterStatus(iter), "(invalid)");
  628. delete iter;
  629. }
  630. TEST(DBTest, IterMulti) {
  631. ASSERT_OK(Put("a", "va"));
  632. ASSERT_OK(Put("b", "vb"));
  633. ASSERT_OK(Put("c", "vc"));
  634. Iterator* iter = db_->NewIterator(ReadOptions());
  635. iter->SeekToFirst();
  636. ASSERT_EQ(IterStatus(iter), "a->va");
  637. iter->Next();
  638. ASSERT_EQ(IterStatus(iter), "b->vb");
  639. iter->Next();
  640. ASSERT_EQ(IterStatus(iter), "c->vc");
  641. iter->Next();
  642. ASSERT_EQ(IterStatus(iter), "(invalid)");
  643. iter->SeekToFirst();
  644. ASSERT_EQ(IterStatus(iter), "a->va");
  645. iter->Prev();
  646. ASSERT_EQ(IterStatus(iter), "(invalid)");
  647. iter->SeekToLast();
  648. ASSERT_EQ(IterStatus(iter), "c->vc");
  649. iter->Prev();
  650. ASSERT_EQ(IterStatus(iter), "b->vb");
  651. iter->Prev();
  652. ASSERT_EQ(IterStatus(iter), "a->va");
  653. iter->Prev();
  654. ASSERT_EQ(IterStatus(iter), "(invalid)");
  655. iter->SeekToLast();
  656. ASSERT_EQ(IterStatus(iter), "c->vc");
  657. iter->Next();
  658. ASSERT_EQ(IterStatus(iter), "(invalid)");
  659. iter->Seek("");
  660. ASSERT_EQ(IterStatus(iter), "a->va");
  661. iter->Seek("a");
  662. ASSERT_EQ(IterStatus(iter), "a->va");
  663. iter->Seek("ax");
  664. ASSERT_EQ(IterStatus(iter), "b->vb");
  665. iter->Seek("b");
  666. ASSERT_EQ(IterStatus(iter), "b->vb");
  667. iter->Seek("z");
  668. ASSERT_EQ(IterStatus(iter), "(invalid)");
  669. // Switch from reverse to forward
  670. iter->SeekToLast();
  671. iter->Prev();
  672. iter->Prev();
  673. iter->Next();
  674. ASSERT_EQ(IterStatus(iter), "b->vb");
  675. // Switch from forward to reverse
  676. iter->SeekToFirst();
  677. iter->Next();
  678. iter->Next();
  679. iter->Prev();
  680. ASSERT_EQ(IterStatus(iter), "b->vb");
  681. // Make sure iter stays at snapshot
  682. ASSERT_OK(Put("a", "va2"));
  683. ASSERT_OK(Put("a2", "va3"));
  684. ASSERT_OK(Put("b", "vb2"));
  685. ASSERT_OK(Put("c", "vc2"));
  686. ASSERT_OK(Delete("b"));
  687. iter->SeekToFirst();
  688. ASSERT_EQ(IterStatus(iter), "a->va");
  689. iter->Next();
  690. ASSERT_EQ(IterStatus(iter), "b->vb");
  691. iter->Next();
  692. ASSERT_EQ(IterStatus(iter), "c->vc");
  693. iter->Next();
  694. ASSERT_EQ(IterStatus(iter), "(invalid)");
  695. iter->SeekToLast();
  696. ASSERT_EQ(IterStatus(iter), "c->vc");
  697. iter->Prev();
  698. ASSERT_EQ(IterStatus(iter), "b->vb");
  699. iter->Prev();
  700. ASSERT_EQ(IterStatus(iter), "a->va");
  701. iter->Prev();
  702. ASSERT_EQ(IterStatus(iter), "(invalid)");
  703. delete iter;
  704. }
  705. TEST(DBTest, IterSmallAndLargeMix) {
  706. ASSERT_OK(Put("a", "va"));
  707. ASSERT_OK(Put("b", std::string(100000, 'b')));
  708. ASSERT_OK(Put("c", "vc"));
  709. ASSERT_OK(Put("d", std::string(100000, 'd')));
  710. ASSERT_OK(Put("e", std::string(100000, 'e')));
  711. Iterator* iter = db_->NewIterator(ReadOptions());
  712. iter->SeekToFirst();
  713. ASSERT_EQ(IterStatus(iter), "a->va");
  714. iter->Next();
  715. ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
  716. iter->Next();
  717. ASSERT_EQ(IterStatus(iter), "c->vc");
  718. iter->Next();
  719. ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
  720. iter->Next();
  721. ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
  722. iter->Next();
  723. ASSERT_EQ(IterStatus(iter), "(invalid)");
  724. iter->SeekToLast();
  725. ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
  726. iter->Prev();
  727. ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
  728. iter->Prev();
  729. ASSERT_EQ(IterStatus(iter), "c->vc");
  730. iter->Prev();
  731. ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
  732. iter->Prev();
  733. ASSERT_EQ(IterStatus(iter), "a->va");
  734. iter->Prev();
  735. ASSERT_EQ(IterStatus(iter), "(invalid)");
  736. delete iter;
  737. }
  738. TEST(DBTest, IterMultiWithDelete) {
  739. do {
  740. ASSERT_OK(Put("a", "va"));
  741. ASSERT_OK(Put("b", "vb"));
  742. ASSERT_OK(Put("c", "vc"));
  743. ASSERT_OK(Delete("b"));
  744. ASSERT_EQ("NOT_FOUND", Get("b"));
  745. Iterator* iter = db_->NewIterator(ReadOptions());
  746. iter->Seek("c");
  747. ASSERT_EQ(IterStatus(iter), "c->vc");
  748. iter->Prev();
  749. ASSERT_EQ(IterStatus(iter), "a->va");
  750. delete iter;
  751. } while (ChangeOptions());
  752. }
  753. TEST(DBTest, Recover) {
  754. do {
  755. ASSERT_OK(Put("foo", "v1"));
  756. ASSERT_OK(Put("baz", "v5"));
  757. Reopen();
  758. ASSERT_EQ("v1", Get("foo"));
  759. ASSERT_EQ("v1", Get("foo"));
  760. ASSERT_EQ("v5", Get("baz"));
  761. ASSERT_OK(Put("bar", "v2"));
  762. ASSERT_OK(Put("foo", "v3"));
  763. Reopen();
  764. ASSERT_EQ("v3", Get("foo"));
  765. ASSERT_OK(Put("foo", "v4"));
  766. ASSERT_EQ("v4", Get("foo"));
  767. ASSERT_EQ("v2", Get("bar"));
  768. ASSERT_EQ("v5", Get("baz"));
  769. } while (ChangeOptions());
  770. }
  771. TEST(DBTest, RecoveryWithEmptyLog) {
  772. do {
  773. ASSERT_OK(Put("foo", "v1"));
  774. ASSERT_OK(Put("foo", "v2"));
  775. Reopen();
  776. Reopen();
  777. ASSERT_OK(Put("foo", "v3"));
  778. Reopen();
  779. ASSERT_EQ("v3", Get("foo"));
  780. } while (ChangeOptions());
  781. }
  782. // Check that writes done during a memtable compaction are recovered
  783. // if the database is shutdown during the memtable compaction.
  784. TEST(DBTest, RecoverDuringMemtableCompaction) {
  785. do {
  786. Options options = CurrentOptions();
  787. options.env = env_;
  788. options.write_buffer_size = 1000000;
  789. Reopen(&options);
  790. // Trigger a long memtable compaction and reopen the database during it
  791. ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file
  792. ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable
  793. ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction
  794. ASSERT_OK(Put("bar", "v2")); // Goes to new log file
  795. Reopen(&options);
  796. ASSERT_EQ("v1", Get("foo"));
  797. ASSERT_EQ("v2", Get("bar"));
  798. ASSERT_EQ(std::string(10000000, 'x'), Get("big1"));
  799. ASSERT_EQ(std::string(1000, 'y'), Get("big2"));
  800. } while (ChangeOptions());
  801. }
  802. static std::string Key(int i) {
  803. char buf[100];
  804. snprintf(buf, sizeof(buf), "key%06d", i);
  805. return std::string(buf);
  806. }
  807. TEST(DBTest, MinorCompactionsHappen) {
  808. Options options = CurrentOptions();
  809. options.write_buffer_size = 10000;
  810. Reopen(&options);
  811. const int N = 500;
  812. int starting_num_tables = TotalTableFiles();
  813. for (int i = 0; i < N; i++) {
  814. ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
  815. }
  816. int ending_num_tables = TotalTableFiles();
  817. ASSERT_GT(ending_num_tables, starting_num_tables);
  818. for (int i = 0; i < N; i++) {
  819. ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
  820. }
  821. Reopen();
  822. for (int i = 0; i < N; i++) {
  823. ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
  824. }
  825. }
  826. TEST(DBTest, RecoverWithLargeLog) {
  827. {
  828. Options options = CurrentOptions();
  829. Reopen(&options);
  830. ASSERT_OK(Put("big1", std::string(200000, '1')));
  831. ASSERT_OK(Put("big2", std::string(200000, '2')));
  832. ASSERT_OK(Put("small3", std::string(10, '3')));
  833. ASSERT_OK(Put("small4", std::string(10, '4')));
  834. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  835. }
  836. // Make sure that if we re-open with a small write buffer size that
  837. // we flush table files in the middle of a large log file.
  838. Options options = CurrentOptions();
  839. options.write_buffer_size = 100000;
  840. Reopen(&options);
  841. ASSERT_EQ(NumTableFilesAtLevel(0), 3);
  842. ASSERT_EQ(std::string(200000, '1'), Get("big1"));
  843. ASSERT_EQ(std::string(200000, '2'), Get("big2"));
  844. ASSERT_EQ(std::string(10, '3'), Get("small3"));
  845. ASSERT_EQ(std::string(10, '4'), Get("small4"));
  846. ASSERT_GT(NumTableFilesAtLevel(0), 1);
  847. }
  848. TEST(DBTest, CompactionsGenerateMultipleFiles) {
  849. Options options = CurrentOptions();
  850. options.write_buffer_size = 100000000; // Large write buffer
  851. Reopen(&options);
  852. Random rnd(301);
  853. // Write 8MB (80 values, each 100K)
  854. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  855. std::vector<std::string> values;
  856. for (int i = 0; i < 80; i++) {
  857. values.push_back(RandomString(&rnd, 100000));
  858. ASSERT_OK(Put(Key(i), values[i]));
  859. }
  860. // Reopening moves updates to level-0
  861. Reopen(&options);
  862. dbfull()->TEST_CompactRange(0, NULL, NULL);
  863. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  864. ASSERT_GT(NumTableFilesAtLevel(1), 1);
  865. for (int i = 0; i < 80; i++) {
  866. ASSERT_EQ(Get(Key(i)), values[i]);
  867. }
  868. }
  869. TEST(DBTest, RepeatedWritesToSameKey) {
  870. Options options = CurrentOptions();
  871. options.env = env_;
  872. options.write_buffer_size = 100000; // Small write buffer
  873. Reopen(&options);
  874. // We must have at most one file per level except for level-0,
  875. // which may have up to kL0_StopWritesTrigger files.
  876. const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger;
  877. Random rnd(301);
  878. std::string value = RandomString(&rnd, 2 * options.write_buffer_size);
  879. for (int i = 0; i < 5 * kMaxFiles; i++) {
  880. Put("key", value);
  881. ASSERT_LE(TotalTableFiles(), kMaxFiles);
  882. fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles());
  883. }
  884. }
  885. TEST(DBTest, SparseMerge) {
  886. Options options = CurrentOptions();
  887. options.compression = kNoCompression;
  888. Reopen(&options);
  889. FillLevels("A", "Z");
  890. // Suppose there is:
  891. // small amount of data with prefix A
  892. // large amount of data with prefix B
  893. // small amount of data with prefix C
  894. // and that recent updates have made small changes to all three prefixes.
  895. // Check that we do not do a compaction that merges all of B in one shot.
  896. const std::string value(1000, 'x');
  897. Put("A", "va");
  898. // Write approximately 100MB of "B" values
  899. for (int i = 0; i < 100000; i++) {
  900. char key[100];
  901. snprintf(key, sizeof(key), "B%010d", i);
  902. Put(key, value);
  903. }
  904. Put("C", "vc");
  905. dbfull()->TEST_CompactMemTable();
  906. dbfull()->TEST_CompactRange(0, NULL, NULL);
  907. // Make sparse update
  908. Put("A", "va2");
  909. Put("B100", "bvalue2");
  910. Put("C", "vc2");
  911. dbfull()->TEST_CompactMemTable();
  912. // Compactions should not cause us to create a situation where
  913. // a file overlaps too much data at the next level.
  914. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  915. dbfull()->TEST_CompactRange(0, NULL, NULL);
  916. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  917. dbfull()->TEST_CompactRange(1, NULL, NULL);
  918. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  919. }
  920. static bool Between(uint64_t val, uint64_t low, uint64_t high) {
  921. bool result = (val >= low) && (val <= high);
  922. if (!result) {
  923. fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
  924. (unsigned long long)(val),
  925. (unsigned long long)(low),
  926. (unsigned long long)(high));
  927. }
  928. return result;
  929. }
  930. TEST(DBTest, ApproximateSizes) {
  931. do {
  932. Options options = CurrentOptions();
  933. options.write_buffer_size = 100000000; // Large write buffer
  934. options.compression = kNoCompression;
  935. DestroyAndReopen();
  936. ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
  937. Reopen(&options);
  938. ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
  939. // Write 8MB (80 values, each 100K)
  940. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  941. const int N = 80;
  942. static const int S1 = 100000;
  943. static const int S2 = 105000; // Allow some expansion from metadata
  944. Random rnd(301);
  945. for (int i = 0; i < N; i++) {
  946. ASSERT_OK(Put(Key(i), RandomString(&rnd, S1)));
  947. }
  948. // 0 because GetApproximateSizes() does not account for memtable space
  949. ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
  950. // Check sizes across recovery by reopening a few times
  951. for (int run = 0; run < 3; run++) {
  952. Reopen(&options);
  953. for (int compact_start = 0; compact_start < N; compact_start += 10) {
  954. for (int i = 0; i < N; i += 10) {
  955. ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i));
  956. ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1)));
  957. ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10));
  958. }
  959. ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50));
  960. ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50));
  961. std::string cstart_str = Key(compact_start);
  962. std::string cend_str = Key(compact_start + 9);
  963. Slice cstart = cstart_str;
  964. Slice cend = cend_str;
  965. dbfull()->TEST_CompactRange(0, &cstart, &cend);
  966. }
  967. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  968. ASSERT_GT(NumTableFilesAtLevel(1), 0);
  969. }
  970. } while (ChangeOptions());
  971. }
  972. TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
  973. do {
  974. Options options = CurrentOptions();
  975. options.compression = kNoCompression;
  976. Reopen();
  977. Random rnd(301);
  978. std::string big1 = RandomString(&rnd, 100000);
  979. ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));
  980. ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));
  981. ASSERT_OK(Put(Key(2), big1));
  982. ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));
  983. ASSERT_OK(Put(Key(4), big1));
  984. ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));
  985. ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
  986. ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
  987. // Check sizes across recovery by reopening a few times
  988. for (int run = 0; run < 3; run++) {
  989. Reopen(&options);
  990. ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));
  991. ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));
  992. ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));
  993. ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));
  994. ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));
  995. ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));
  996. ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));
  997. ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));
  998. ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000));
  999. ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));
  1000. dbfull()->TEST_CompactRange(0, NULL, NULL);
  1001. }
  1002. } while (ChangeOptions());
  1003. }
  1004. TEST(DBTest, IteratorPinsRef) {
  1005. Put("foo", "hello");
  1006. // Get iterator that will yield the current contents of the DB.
  1007. Iterator* iter = db_->NewIterator(ReadOptions());
  1008. // Write to force compactions
  1009. Put("foo", "newvalue1");
  1010. for (int i = 0; i < 100; i++) {
  1011. ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
  1012. }
  1013. Put("foo", "newvalue2");
  1014. iter->SeekToFirst();
  1015. ASSERT_TRUE(iter->Valid());
  1016. ASSERT_EQ("foo", iter->key().ToString());
  1017. ASSERT_EQ("hello", iter->value().ToString());
  1018. iter->Next();
  1019. ASSERT_TRUE(!iter->Valid());
  1020. delete iter;
  1021. }
  1022. TEST(DBTest, Snapshot) {
  1023. do {
  1024. Put("foo", "v1");
  1025. const Snapshot* s1 = db_->GetSnapshot();
  1026. Put("foo", "v2");
  1027. const Snapshot* s2 = db_->GetSnapshot();
  1028. Put("foo", "v3");
  1029. const Snapshot* s3 = db_->GetSnapshot();
  1030. Put("foo", "v4");
  1031. ASSERT_EQ("v1", Get("foo", s1));
  1032. ASSERT_EQ("v2", Get("foo", s2));
  1033. ASSERT_EQ("v3", Get("foo", s3));
  1034. ASSERT_EQ("v4", Get("foo"));
  1035. db_->ReleaseSnapshot(s3);
  1036. ASSERT_EQ("v1", Get("foo", s1));
  1037. ASSERT_EQ("v2", Get("foo", s2));
  1038. ASSERT_EQ("v4", Get("foo"));
  1039. db_->ReleaseSnapshot(s1);
  1040. ASSERT_EQ("v2", Get("foo", s2));
  1041. ASSERT_EQ("v4", Get("foo"));
  1042. db_->ReleaseSnapshot(s2);
  1043. ASSERT_EQ("v4", Get("foo"));
  1044. } while (ChangeOptions());
  1045. }
  1046. TEST(DBTest, HiddenValuesAreRemoved) {
  1047. do {
  1048. Random rnd(301);
  1049. FillLevels("a", "z");
  1050. std::string big = RandomString(&rnd, 50000);
  1051. Put("foo", big);
  1052. Put("pastfoo", "v");
  1053. const Snapshot* snapshot = db_->GetSnapshot();
  1054. Put("foo", "tiny");
  1055. Put("pastfoo2", "v2"); // Advance sequence number one more
  1056. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  1057. ASSERT_GT(NumTableFilesAtLevel(0), 0);
  1058. ASSERT_EQ(big, Get("foo", snapshot));
  1059. ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));
  1060. db_->ReleaseSnapshot(snapshot);
  1061. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");
  1062. Slice x("x");
  1063. dbfull()->TEST_CompactRange(0, NULL, &x);
  1064. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
  1065. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  1066. ASSERT_GE(NumTableFilesAtLevel(1), 1);
  1067. dbfull()->TEST_CompactRange(1, NULL, &x);
  1068. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
  1069. ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));
  1070. } while (ChangeOptions());
  1071. }
  1072. TEST(DBTest, DeletionMarkers1) {
  1073. Put("foo", "v1");
  1074. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  1075. const int last = config::kMaxMemCompactLevel;
  1076. ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
  1077. // Place a table at level last-1 to prevent merging with preceding mutation
  1078. Put("a", "begin");
  1079. Put("z", "end");
  1080. dbfull()->TEST_CompactMemTable();
  1081. ASSERT_EQ(NumTableFilesAtLevel(last), 1);
  1082. ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);
  1083. Delete("foo");
  1084. Put("foo", "v2");
  1085. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
  1086. ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
  1087. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
  1088. Slice z("z");
  1089. dbfull()->TEST_CompactRange(last-2, NULL, &z);
  1090. // DEL eliminated, but v1 remains because we aren't compacting that level
  1091. // (DEL can be eliminated because v2 hides v1).
  1092. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");
  1093. dbfull()->TEST_CompactRange(last-1, NULL, NULL);
  1094. // Merging last-1 w/ last, so we are the base level for "foo", so
  1095. // DEL is removed. (as is v1).
  1096. ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");
  1097. }
  1098. TEST(DBTest, DeletionMarkers2) {
  1099. Put("foo", "v1");
  1100. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  1101. const int last = config::kMaxMemCompactLevel;
  1102. ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
  1103. // Place a table at level last-1 to prevent merging with preceding mutation
  1104. Put("a", "begin");
  1105. Put("z", "end");
  1106. dbfull()->TEST_CompactMemTable();
  1107. ASSERT_EQ(NumTableFilesAtLevel(last), 1);
  1108. ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);
  1109. Delete("foo");
  1110. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  1111. ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
  1112. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  1113. dbfull()->TEST_CompactRange(last-2, NULL, NULL);
  1114. // DEL kept: "last" file overlaps
  1115. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  1116. dbfull()->TEST_CompactRange(last-1, NULL, NULL);
  1117. // Merging last-1 w/ last, so we are the base level for "foo", so
  1118. // DEL is removed. (as is v1).
  1119. ASSERT_EQ(AllEntriesFor("foo"), "[ ]");
  1120. }
  1121. TEST(DBTest, OverlapInLevel0) {
  1122. do {
  1123. ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config";
  1124. // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0.
  1125. ASSERT_OK(Put("100", "v100"));
  1126. ASSERT_OK(Put("999", "v999"));
  1127. dbfull()->TEST_CompactMemTable();
  1128. ASSERT_OK(Delete("100"));
  1129. ASSERT_OK(Delete("999"));
  1130. dbfull()->TEST_CompactMemTable();
  1131. ASSERT_EQ("0,1,1", FilesPerLevel());
  1132. // Make files spanning the following ranges in level-0:
  1133. // files[0] 200 .. 900
  1134. // files[1] 300 .. 500
  1135. // Note that files are sorted by smallest key.
  1136. ASSERT_OK(Put("300", "v300"));
  1137. ASSERT_OK(Put("500", "v500"));
  1138. dbfull()->TEST_CompactMemTable();
  1139. ASSERT_OK(Put("200", "v200"));
  1140. ASSERT_OK(Put("600", "v600"));
  1141. ASSERT_OK(Put("900", "v900"));
  1142. dbfull()->TEST_CompactMemTable();
  1143. ASSERT_EQ("2,1,1", FilesPerLevel());
  1144. // Compact away the placeholder files we created initially
  1145. dbfull()->TEST_CompactRange(1, NULL, NULL);
  1146. dbfull()->TEST_CompactRange(2, NULL, NULL);
  1147. ASSERT_EQ("2", FilesPerLevel());
  1148. // Do a memtable compaction. Before bug-fix, the compaction would
  1149. // not detect the overlap with level-0 files and would incorrectly place
  1150. // the deletion in a deeper level.
  1151. ASSERT_OK(Delete("600"));
  1152. dbfull()->TEST_CompactMemTable();
  1153. ASSERT_EQ("3", FilesPerLevel());
  1154. ASSERT_EQ("NOT_FOUND", Get("600"));
  1155. } while (ChangeOptions());
  1156. }
  1157. TEST(DBTest, L0_CompactionBug_Issue44_a) {
  1158. Reopen();
  1159. ASSERT_OK(Put("b", "v"));
  1160. Reopen();
  1161. ASSERT_OK(Delete("b"));
  1162. ASSERT_OK(Delete("a"));
  1163. Reopen();
  1164. ASSERT_OK(Delete("a"));
  1165. Reopen();
  1166. ASSERT_OK(Put("a", "v"));
  1167. Reopen();
  1168. Reopen();
  1169. ASSERT_EQ("(a->v)", Contents());
  1170. DelayMilliseconds(1000); // Wait for compaction to finish
  1171. ASSERT_EQ("(a->v)", Contents());
  1172. }
  1173. TEST(DBTest, L0_CompactionBug_Issue44_b) {
  1174. Reopen();
  1175. Put("","");
  1176. Reopen();
  1177. Delete("e");
  1178. Put("","");
  1179. Reopen();
  1180. Put("c", "cv");
  1181. Reopen();
  1182. Put("","");
  1183. Reopen();
  1184. Put("","");
  1185. DelayMilliseconds(1000); // Wait for compaction to finish
  1186. Reopen();
  1187. Put("d","dv");
  1188. Reopen();
  1189. Put("","");
  1190. Reopen();
  1191. Delete("d");
  1192. Delete("b");
  1193. Reopen();
  1194. ASSERT_EQ("(->)(c->cv)", Contents());
  1195. DelayMilliseconds(1000); // Wait for compaction to finish
  1196. ASSERT_EQ("(->)(c->cv)", Contents());
  1197. }
  1198. TEST(DBTest, ComparatorCheck) {
  1199. class NewComparator : public Comparator {
  1200. public:
  1201. virtual const char* Name() const { return "leveldb.NewComparator"; }
  1202. virtual int Compare(const Slice& a, const Slice& b) const {
  1203. return BytewiseComparator()->Compare(a, b);
  1204. }
  1205. virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
  1206. BytewiseComparator()->FindShortestSeparator(s, l);
  1207. }
  1208. virtual void FindShortSuccessor(std::string* key) const {
  1209. BytewiseComparator()->FindShortSuccessor(key);
  1210. }
  1211. };
  1212. NewComparator cmp;
  1213. Options new_options = CurrentOptions();
  1214. new_options.comparator = &cmp;
  1215. Status s = TryReopen(&new_options);
  1216. ASSERT_TRUE(!s.ok());
  1217. ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos)
  1218. << s.ToString();
  1219. }
  1220. TEST(DBTest, CustomComparator) {
  1221. class NumberComparator : public Comparator {
  1222. public:
  1223. virtual const char* Name() const { return "test.NumberComparator"; }
  1224. virtual int Compare(const Slice& a, const Slice& b) const {
  1225. return ToNumber(a) - ToNumber(b);
  1226. }
  1227. virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
  1228. ToNumber(*s); // Check format
  1229. ToNumber(l); // Check format
  1230. }
  1231. virtual void FindShortSuccessor(std::string* key) const {
  1232. ToNumber(*key); // Check format
  1233. }
  1234. private:
  1235. static int ToNumber(const Slice& x) {
  1236. // Check that there are no extra characters.
  1237. ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']')
  1238. << EscapeString(x);
  1239. int val;
  1240. char ignored;
  1241. ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1)
  1242. << EscapeString(x);
  1243. return val;
  1244. }
  1245. };
  1246. NumberComparator cmp;
  1247. Options new_options = CurrentOptions();
  1248. new_options.create_if_missing = true;
  1249. new_options.comparator = &cmp;
  1250. new_options.filter_policy = NULL; // Cannot use bloom filters
  1251. new_options.write_buffer_size = 1000; // Compact more often
  1252. DestroyAndReopen(&new_options);
  1253. ASSERT_OK(Put("[10]", "ten"));
  1254. ASSERT_OK(Put("[0x14]", "twenty"));
  1255. for (int i = 0; i < 2; i++) {
  1256. ASSERT_EQ("ten", Get("[10]"));
  1257. ASSERT_EQ("ten", Get("[0xa]"));
  1258. ASSERT_EQ("twenty", Get("[20]"));
  1259. ASSERT_EQ("twenty", Get("[0x14]"));
  1260. ASSERT_EQ("NOT_FOUND", Get("[15]"));
  1261. ASSERT_EQ("NOT_FOUND", Get("[0xf]"));
  1262. Compact("[0]", "[9999]");
  1263. }
  1264. for (int run = 0; run < 2; run++) {
  1265. for (int i = 0; i < 1000; i++) {
  1266. char buf[100];
  1267. snprintf(buf, sizeof(buf), "[%d]", i*10);
  1268. ASSERT_OK(Put(buf, buf));
  1269. }
  1270. Compact("[0]", "[1000000]");
  1271. }
  1272. }
  1273. TEST(DBTest, ManualCompaction) {
  1274. ASSERT_EQ(config::kMaxMemCompactLevel, 2)
  1275. << "Need to update this test to match kMaxMemCompactLevel";
  1276. MakeTables(3, "p", "q");
  1277. ASSERT_EQ("1,1,1", FilesPerLevel());
  1278. // Compaction range falls before files
  1279. Compact("", "c");
  1280. ASSERT_EQ("1,1,1", FilesPerLevel());
  1281. // Compaction range falls after files
  1282. Compact("r", "z");
  1283. ASSERT_EQ("1,1,1", FilesPerLevel());
  1284. // Compaction range overlaps files
  1285. Compact("p1", "p9");
  1286. ASSERT_EQ("0,0,1", FilesPerLevel());
  1287. // Populate a different range
  1288. MakeTables(3, "c", "e");
  1289. ASSERT_EQ("1,1,2", FilesPerLevel());
  1290. // Compact just the new range
  1291. Compact("b", "f");
  1292. ASSERT_EQ("0,0,2", FilesPerLevel());
  1293. // Compact all
  1294. MakeTables(1, "a", "z");
  1295. ASSERT_EQ("0,1,2", FilesPerLevel());
  1296. db_->CompactRange(NULL, NULL);
  1297. ASSERT_EQ("0,0,1", FilesPerLevel());
  1298. }
  1299. TEST(DBTest, DBOpen_Options) {
  1300. std::string dbname = test::TmpDir() + "/db_options_test";
  1301. DestroyDB(dbname, Options());
  1302. // Does not exist, and create_if_missing == false: error
  1303. DB* db = NULL;
  1304. Options opts;
  1305. opts.create_if_missing = false;
  1306. Status s = DB::Open(opts, dbname, &db);
  1307. ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL);
  1308. ASSERT_TRUE(db == NULL);
  1309. // Does not exist, and create_if_missing == true: OK
  1310. opts.create_if_missing = true;
  1311. s = DB::Open(opts, dbname, &db);
  1312. ASSERT_OK(s);
  1313. ASSERT_TRUE(db != NULL);
  1314. delete db;
  1315. db = NULL;
  1316. // Does exist, and error_if_exists == true: error
  1317. opts.create_if_missing = false;
  1318. opts.error_if_exists = true;
  1319. s = DB::Open(opts, dbname, &db);
  1320. ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL);
  1321. ASSERT_TRUE(db == NULL);
  1322. // Does exist, and error_if_exists == false: OK
  1323. opts.create_if_missing = true;
  1324. opts.error_if_exists = false;
  1325. s = DB::Open(opts, dbname, &db);
  1326. ASSERT_OK(s);
  1327. ASSERT_TRUE(db != NULL);
  1328. delete db;
  1329. db = NULL;
  1330. }
  1331. TEST(DBTest, Locking) {
  1332. DB* db2 = NULL;
  1333. Status s = DB::Open(CurrentOptions(), dbname_, &db2);
  1334. ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db";
  1335. }
  1336. // Check that number of files does not grow when we are out of space
  1337. TEST(DBTest, NoSpace) {
  1338. Options options = CurrentOptions();
  1339. options.env = env_;
  1340. Reopen(&options);
  1341. ASSERT_OK(Put("foo", "v1"));
  1342. ASSERT_EQ("v1", Get("foo"));
  1343. Compact("a", "z");
  1344. const int num_files = CountFiles();
  1345. env_->no_space_.Release_Store(env_); // Force out-of-space errors
  1346. for (int i = 0; i < 10; i++) {
  1347. for (int level = 0; level < config::kNumLevels-1; level++) {
  1348. dbfull()->TEST_CompactRange(level, NULL, NULL);
  1349. }
  1350. }
  1351. env_->no_space_.Release_Store(NULL);
  1352. ASSERT_LT(CountFiles(), num_files + 3);
  1353. }
  1354. TEST(DBTest, NonWritableFileSystem) {
  1355. Options options = CurrentOptions();
  1356. options.write_buffer_size = 1000;
  1357. options.env = env_;
  1358. Reopen(&options);
  1359. ASSERT_OK(Put("foo", "v1"));
  1360. env_->non_writable_.Release_Store(env_); // Force errors for new files
  1361. std::string big(100000, 'x');
  1362. int errors = 0;
  1363. for (int i = 0; i < 20; i++) {
  1364. fprintf(stderr, "iter %d; errors %d\n", i, errors);
  1365. if (!Put("foo", big).ok()) {
  1366. errors++;
  1367. DelayMilliseconds(100);
  1368. }
  1369. }
  1370. ASSERT_GT(errors, 0);
  1371. env_->non_writable_.Release_Store(NULL);
  1372. }
  1373. TEST(DBTest, WriteSyncError) {
  1374. // Check that log sync errors cause the DB to disallow future writes.
  1375. // (a) Cause log sync calls to fail
  1376. Options options = CurrentOptions();
  1377. options.env = env_;
  1378. Reopen(&options);
  1379. env_->data_sync_error_.Release_Store(env_);
  1380. // (b) Normal write should succeed
  1381. WriteOptions w;
  1382. ASSERT_OK(db_->Put(w, "k1", "v1"));
  1383. ASSERT_EQ("v1", Get("k1"));
  1384. // (c) Do a sync write; should fail
  1385. w.sync = true;
  1386. ASSERT_TRUE(!db_->Put(w, "k2", "v2").ok());
  1387. ASSERT_EQ("v1", Get("k1"));
  1388. ASSERT_EQ("NOT_FOUND", Get("k2"));
  1389. // (d) make sync behave normally
  1390. env_->data_sync_error_.Release_Store(NULL);
  1391. // (e) Do a non-sync write; should fail
  1392. w.sync = false;
  1393. ASSERT_TRUE(!db_->Put(w, "k3", "v3").ok());
  1394. ASSERT_EQ("v1", Get("k1"));
  1395. ASSERT_EQ("NOT_FOUND", Get("k2"));
  1396. ASSERT_EQ("NOT_FOUND", Get("k3"));
  1397. }
  1398. TEST(DBTest, ManifestWriteError) {
  1399. // Test for the following problem:
  1400. // (a) Compaction produces file F
  1401. // (b) Log record containing F is written to MANIFEST file, but Sync() fails
  1402. // (c) GC deletes F
  1403. // (d) After reopening DB, reads fail since deleted F is named in log record
  1404. // We iterate twice. In the second iteration, everything is the
  1405. // same except the log record never makes it to the MANIFEST file.
  1406. for (int iter = 0; iter < 2; iter++) {
  1407. port::AtomicPointer* error_type = (iter == 0)
  1408. ? &env_->manifest_sync_error_
  1409. : &env_->manifest_write_error_;
  1410. // Insert foo=>bar mapping
  1411. Options options = CurrentOptions();
  1412. options.env = env_;
  1413. options.create_if_missing = true;
  1414. options.error_if_exists = false;
  1415. DestroyAndReopen(&options);
  1416. ASSERT_OK(Put("foo", "bar"));
  1417. ASSERT_EQ("bar", Get("foo"));
  1418. // Memtable compaction (will succeed)
  1419. dbfull()->TEST_CompactMemTable();
  1420. ASSERT_EQ("bar", Get("foo"));
  1421. const int last = config::kMaxMemCompactLevel;
  1422. ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level
  1423. // Merging compaction (will fail)
  1424. error_type->Release_Store(env_);
  1425. dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail
  1426. ASSERT_EQ("bar", Get("foo"));
  1427. // Recovery: should not lose data
  1428. error_type->Release_Store(NULL);
  1429. Reopen(&options);
  1430. ASSERT_EQ("bar", Get("foo"));
  1431. }
  1432. }
  1433. TEST(DBTest, MissingSSTFile) {
  1434. ASSERT_OK(Put("foo", "bar"));
  1435. ASSERT_EQ("bar", Get("foo"));
  1436. // Dump the memtable to disk.
  1437. dbfull()->TEST_CompactMemTable();
  1438. ASSERT_EQ("bar", Get("foo"));
  1439. Close();
  1440. ASSERT_TRUE(DeleteAnSSTFile());
  1441. Options options = CurrentOptions();
  1442. options.paranoid_checks = true;
  1443. Status s = TryReopen(&options);
  1444. ASSERT_TRUE(!s.ok());
  1445. ASSERT_TRUE(s.ToString().find("issing") != std::string::npos)
  1446. << s.ToString();
  1447. }
  1448. TEST(DBTest, StillReadSST) {
  1449. ASSERT_OK(Put("foo", "bar"));
  1450. ASSERT_EQ("bar", Get("foo"));
  1451. // Dump the memtable to disk.
  1452. dbfull()->TEST_CompactMemTable();
  1453. ASSERT_EQ("bar", Get("foo"));
  1454. Close();
  1455. ASSERT_GT(RenameLDBToSST(), 0);
  1456. Options options = CurrentOptions();
  1457. options.paranoid_checks = true;
  1458. Status s = TryReopen(&options);
  1459. ASSERT_TRUE(s.ok());
  1460. ASSERT_EQ("bar", Get("foo"));
  1461. }
  1462. TEST(DBTest, FilesDeletedAfterCompaction) {
  1463. ASSERT_OK(Put("foo", "v2"));
  1464. Compact("a", "z");
  1465. const int num_files = CountFiles();
  1466. for (int i = 0; i < 10; i++) {
  1467. ASSERT_OK(Put("foo", "v2"));
  1468. Compact("a", "z");
  1469. }
  1470. ASSERT_EQ(CountFiles(), num_files);
  1471. }
  1472. TEST(DBTest, BloomFilter) {
  1473. env_->count_random_reads_ = true;
  1474. Options options = CurrentOptions();
  1475. options.env = env_;
  1476. options.block_cache = NewLRUCache(0); // Prevent cache hits
  1477. options.filter_policy = NewBloomFilterPolicy(10);
  1478. Reopen(&options);
  1479. // Populate multiple layers
  1480. const int N = 10000;
  1481. for (int i = 0; i < N; i++) {
  1482. ASSERT_OK(Put(Key(i), Key(i)));
  1483. }
  1484. Compact("a", "z");
  1485. for (int i = 0; i < N; i += 100) {
  1486. ASSERT_OK(Put(Key(i), Key(i)));
  1487. }
  1488. dbfull()->TEST_CompactMemTable();
  1489. // Prevent auto compactions triggered by seeks
  1490. env_->delay_data_sync_.Release_Store(env_);
  1491. // Lookup present keys. Should rarely read from small sstable.
  1492. env_->random_read_counter_.Reset();
  1493. for (int i = 0; i < N; i++) {
  1494. ASSERT_EQ(Key(i), Get(Key(i)));
  1495. }
  1496. int reads = env_->random_read_counter_.Read();
  1497. fprintf(stderr, "%d present => %d reads\n", N, reads);
  1498. ASSERT_GE(reads, N);
  1499. ASSERT_LE(reads, N + 2*N/100);
  1500. // Lookup present keys. Should rarely read from either sstable.
  1501. env_->random_read_counter_.Reset();
  1502. for (int i = 0; i < N; i++) {
  1503. ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing"));
  1504. }
  1505. reads = env_->random_read_counter_.Read();
  1506. fprintf(stderr, "%d missing => %d reads\n", N, reads);
  1507. ASSERT_LE(reads, 3*N/100);
  1508. env_->delay_data_sync_.Release_Store(NULL);
  1509. Close();
  1510. delete options.block_cache;
  1511. delete options.filter_policy;
  1512. }
  1513. // Multi-threaded test:
  1514. namespace {
  1515. static const int kNumThreads = 4;
  1516. static const int kTestSeconds = 10;
  1517. static const int kNumKeys = 1000;
  1518. struct MTState {
  1519. DBTest* test;
  1520. port::AtomicPointer stop;
  1521. port::AtomicPointer counter[kNumThreads];
  1522. port::AtomicPointer thread_done[kNumThreads];
  1523. };
  1524. struct MTThread {
  1525. MTState* state;
  1526. int id;
  1527. };
  1528. static void MTThreadBody(void* arg) {
  1529. MTThread* t = reinterpret_cast<MTThread*>(arg);
  1530. int id = t->id;
  1531. DB* db = t->state->test->db_;
  1532. uintptr_t counter = 0;
  1533. fprintf(stderr, "... starting thread %d\n", id);
  1534. Random rnd(1000 + id);
  1535. std::string value;
  1536. char valbuf[1500];
  1537. while (t->state->stop.Acquire_Load() == NULL) {
  1538. t->state->counter[id].Release_Store(reinterpret_cast<void*>(counter));
  1539. int key = rnd.Uniform(kNumKeys);
  1540. char keybuf[20];
  1541. snprintf(keybuf, sizeof(keybuf), "%016d", key);
  1542. if (rnd.OneIn(2)) {
  1543. // Write values of the form <key, my id, counter>.
  1544. // We add some padding for force compactions.
  1545. snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d",
  1546. key, id, static_cast<int>(counter));
  1547. ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));
  1548. } else {
  1549. // Read a value and verify that it matches the pattern written above.
  1550. Status s = db->Get(ReadOptions(), Slice(keybuf), &value);
  1551. if (s.IsNotFound()) {
  1552. // Key has not yet been written
  1553. } else {
  1554. // Check that the writer thread counter is >= the counter in the value
  1555. ASSERT_OK(s);
  1556. int k, w, c;
  1557. ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value;
  1558. ASSERT_EQ(k, key);
  1559. ASSERT_GE(w, 0);
  1560. ASSERT_LT(w, kNumThreads);
  1561. ASSERT_LE(static_cast<uintptr_t>(c), reinterpret_cast<uintptr_t>(
  1562. t->state->counter[w].Acquire_Load()));
  1563. }
  1564. }
  1565. counter++;
  1566. }
  1567. t->state->thread_done[id].Release_Store(t);
  1568. fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter));
  1569. }
  1570. } // namespace
  1571. TEST(DBTest, MultiThreaded) {
  1572. do {
  1573. // Initialize state
  1574. MTState mt;
  1575. mt.test = this;
  1576. mt.stop.Release_Store(0);
  1577. for (int id = 0; id < kNumThreads; id++) {
  1578. mt.counter[id].Release_Store(0);
  1579. mt.thread_done[id].Release_Store(0);
  1580. }
  1581. // Start threads
  1582. MTThread thread[kNumThreads];
  1583. for (int id = 0; id < kNumThreads; id++) {
  1584. thread[id].state = &mt;
  1585. thread[id].id = id;
  1586. env_->StartThread(MTThreadBody, &thread[id]);
  1587. }
  1588. // Let them run for a while
  1589. DelayMilliseconds(kTestSeconds * 1000);
  1590. // Stop the threads and wait for them to finish
  1591. mt.stop.Release_Store(&mt);
  1592. for (int id = 0; id < kNumThreads; id++) {
  1593. while (mt.thread_done[id].Acquire_Load() == NULL) {
  1594. DelayMilliseconds(100);
  1595. }
  1596. }
  1597. } while (ChangeOptions());
  1598. }
  1599. namespace {
  1600. typedef std::map<std::string, std::string> KVMap;
  1601. }
  1602. class ModelDB: public DB {
  1603. public:
  1604. class ModelSnapshot : public Snapshot {
  1605. public:
  1606. KVMap map_;
  1607. };
  1608. explicit ModelDB(const Options& options): options_(options) { }
  1609. ~ModelDB() { }
  1610. virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) {
  1611. return DB::Put(o, k, v);
  1612. }
  1613. virtual Status Delete(const WriteOptions& o, const Slice& key) {
  1614. return DB::Delete(o, key);
  1615. }
  1616. virtual Status Get(const ReadOptions& options,
  1617. const Slice& key, std::string* value) {
  1618. assert(false); // Not implemented
  1619. return Status::NotFound(key);
  1620. }
  1621. virtual Iterator* NewIterator(const ReadOptions& options) {
  1622. if (options.snapshot == NULL) {
  1623. KVMap* saved = new KVMap;
  1624. *saved = map_;
  1625. return new ModelIter(saved, true);
  1626. } else {
  1627. const KVMap* snapshot_state =
  1628. &(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);
  1629. return new ModelIter(snapshot_state, false);
  1630. }
  1631. }
  1632. virtual const Snapshot* GetSnapshot() {
  1633. ModelSnapshot* snapshot = new ModelSnapshot;
  1634. snapshot->map_ = map_;
  1635. return snapshot;
  1636. }
  1637. virtual void ReleaseSnapshot(const Snapshot* snapshot) {
  1638. delete reinterpret_cast<const ModelSnapshot*>(snapshot);
  1639. }
  1640. virtual Status Write(const WriteOptions& options, WriteBatch* batch) {
  1641. class Handler : public WriteBatch::Handler {
  1642. public:
  1643. KVMap* map_;
  1644. virtual void Put(const Slice& key, const Slice& value) {
  1645. (*map_)[key.ToString()] = value.ToString();
  1646. }
  1647. virtual void Delete(const Slice& key) {
  1648. map_->erase(key.ToString());
  1649. }
  1650. };
  1651. Handler handler;
  1652. handler.map_ = &map_;
  1653. return batch->Iterate(&handler);
  1654. }
  1655. virtual bool GetProperty(const Slice& property, std::string* value) {
  1656. return false;
  1657. }
  1658. virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) {
  1659. for (int i = 0; i < n; i++) {
  1660. sizes[i] = 0;
  1661. }
  1662. }
  1663. virtual void CompactRange(const Slice* start, const Slice* end) {
  1664. }
  1665. private:
  1666. class ModelIter: public Iterator {
  1667. public:
  1668. ModelIter(const KVMap* map, bool owned)
  1669. : map_(map), owned_(owned), iter_(map_->end()) {
  1670. }
  1671. ~ModelIter() {
  1672. if (owned_) delete map_;
  1673. }
  1674. virtual bool Valid() const { return iter_ != map_->end(); }
  1675. virtual void SeekToFirst() { iter_ = map_->begin(); }
  1676. virtual void SeekToLast() {
  1677. if (map_->empty()) {
  1678. iter_ = map_->end();
  1679. } else {
  1680. iter_ = map_->find(map_->rbegin()->first);
  1681. }
  1682. }
  1683. virtual void Seek(const Slice& k) {
  1684. iter_ = map_->lower_bound(k.ToString());
  1685. }
  1686. virtual void Next() { ++iter_; }
  1687. virtual void Prev() { --iter_; }
  1688. virtual Slice key() const { return iter_->first; }
  1689. virtual Slice value() const { return iter_->second; }
  1690. virtual Status status() const { return Status::OK(); }
  1691. private:
  1692. const KVMap* const map_;
  1693. const bool owned_; // Do we own map_
  1694. KVMap::const_iterator iter_;
  1695. };
  1696. const Options options_;
  1697. KVMap map_;
  1698. };
  1699. static std::string RandomKey(Random* rnd) {
  1700. int len = (rnd->OneIn(3)
  1701. ? 1 // Short sometimes to encourage collisions
  1702. : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));
  1703. return test::RandomKey(rnd, len);
  1704. }
  1705. static bool CompareIterators(int step,
  1706. DB* model,
  1707. DB* db,
  1708. const Snapshot* model_snap,
  1709. const Snapshot* db_snap) {
  1710. ReadOptions options;
  1711. options.snapshot = model_snap;
  1712. Iterator* miter = model->NewIterator(options);
  1713. options.snapshot = db_snap;
  1714. Iterator* dbiter = db->NewIterator(options);
  1715. bool ok = true;
  1716. int count = 0;
  1717. for (miter->SeekToFirst(), dbiter->SeekToFirst();
  1718. ok && miter->Valid() && dbiter->Valid();
  1719. miter->Next(), dbiter->Next()) {
  1720. count++;
  1721. if (miter->key().compare(dbiter->key()) != 0) {
  1722. fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n",
  1723. step,
  1724. EscapeString(miter->key()).c_str(),
  1725. EscapeString(dbiter->key()).c_str());
  1726. ok = false;
  1727. break;
  1728. }
  1729. if (miter->value().compare(dbiter->value()) != 0) {
  1730. fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
  1731. step,
  1732. EscapeString(miter->key()).c_str(),
  1733. EscapeString(miter->value()).c_str(),
  1734. EscapeString(miter->value()).c_str());
  1735. ok = false;
  1736. }
  1737. }
  1738. if (ok) {
  1739. if (miter->Valid() != dbiter->Valid()) {
  1740. fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
  1741. step, miter->Valid(), dbiter->Valid());
  1742. ok = false;
  1743. }
  1744. }
  1745. fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
  1746. delete miter;
  1747. delete dbiter;
  1748. return ok;
  1749. }
  1750. TEST(DBTest, Randomized) {
  1751. Random rnd(test::RandomSeed());
  1752. do {
  1753. ModelDB model(CurrentOptions());
  1754. const int N = 10000;
  1755. const Snapshot* model_snap = NULL;
  1756. const Snapshot* db_snap = NULL;
  1757. std::string k, v;
  1758. for (int step = 0; step < N; step++) {
  1759. if (step % 100 == 0) {
  1760. fprintf(stderr, "Step %d of %d\n", step, N);
  1761. }
  1762. // TODO(sanjay): Test Get() works
  1763. int p = rnd.Uniform(100);
  1764. if (p < 45) { // Put
  1765. k = RandomKey(&rnd);
  1766. v = RandomString(&rnd,
  1767. rnd.OneIn(20)
  1768. ? 100 + rnd.Uniform(100)
  1769. : rnd.Uniform(8));
  1770. ASSERT_OK(model.Put(WriteOptions(), k, v));
  1771. ASSERT_OK(db_->Put(WriteOptions(), k, v));
  1772. } else if (p < 90) { // Delete
  1773. k = RandomKey(&rnd);
  1774. ASSERT_OK(model.Delete(WriteOptions(), k));
  1775. ASSERT_OK(db_->Delete(WriteOptions(), k));
  1776. } else { // Multi-element batch
  1777. WriteBatch b;
  1778. const int num = rnd.Uniform(8);
  1779. for (int i = 0; i < num; i++) {
  1780. if (i == 0 || !rnd.OneIn(10)) {
  1781. k = RandomKey(&rnd);
  1782. } else {
  1783. // Periodically re-use the same key from the previous iter, so
  1784. // we have multiple entries in the write batch for the same key
  1785. }
  1786. if (rnd.OneIn(2)) {
  1787. v = RandomString(&rnd, rnd.Uniform(10));
  1788. b.Put(k, v);
  1789. } else {
  1790. b.Delete(k);
  1791. }
  1792. }
  1793. ASSERT_OK(model.Write(WriteOptions(), &b));
  1794. ASSERT_OK(db_->Write(WriteOptions(), &b));
  1795. }
  1796. if ((step % 100) == 0) {
  1797. ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
  1798. ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));
  1799. // Save a snapshot from each DB this time that we'll use next
  1800. // time we compare things, to make sure the current state is
  1801. // preserved with the snapshot
  1802. if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
  1803. if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
  1804. Reopen();
  1805. ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
  1806. model_snap = model.GetSnapshot();
  1807. db_snap = db_->GetSnapshot();
  1808. }
  1809. }
  1810. if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
  1811. if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
  1812. } while (ChangeOptions());
  1813. }
  1814. std::string MakeKey(unsigned int num) {
  1815. char buf[30];
  1816. snprintf(buf, sizeof(buf), "%016u", num);
  1817. return std::string(buf);
  1818. }
  1819. void BM_LogAndApply(int iters, int num_base_files) {
  1820. std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";
  1821. DestroyDB(dbname, Options());
  1822. DB* db = NULL;
  1823. Options opts;
  1824. opts.create_if_missing = true;
  1825. Status s = DB::Open(opts, dbname, &db);
  1826. ASSERT_OK(s);
  1827. ASSERT_TRUE(db != NULL);
  1828. delete db;
  1829. db = NULL;
  1830. Env* env = Env::Default();
  1831. port::Mutex mu;
  1832. MutexLock l(&mu);
  1833. InternalKeyComparator cmp(BytewiseComparator());
  1834. Options options;
  1835. VersionSet vset(dbname, &options, NULL, &cmp);
  1836. ASSERT_OK(vset.Recover());
  1837. VersionEdit vbase;
  1838. uint64_t fnum = 1;
  1839. for (int i = 0; i < num_base_files; i++) {
  1840. InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
  1841. InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
  1842. vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);
  1843. }
  1844. ASSERT_OK(vset.LogAndApply(&vbase, &mu));
  1845. uint64_t start_micros = env->NowMicros();
  1846. for (int i = 0; i < iters; i++) {
  1847. VersionEdit vedit;
  1848. vedit.DeleteFile(2, fnum);
  1849. InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
  1850. InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
  1851. vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);
  1852. vset.LogAndApply(&vedit, &mu);
  1853. }
  1854. uint64_t stop_micros = env->NowMicros();
  1855. unsigned int us = stop_micros - start_micros;
  1856. char buf[16];
  1857. snprintf(buf, sizeof(buf), "%d", num_base_files);
  1858. fprintf(stderr,
  1859. "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n",
  1860. buf, iters, us, ((float)us) / iters);
  1861. }
  1862. } // namespace leveldb
  1863. int main(int argc, char** argv) {
  1864. if (argc > 1 && std::string(argv[1]) == "--benchmark") {
  1865. leveldb::BM_LogAndApply(1000, 1);
  1866. leveldb::BM_LogAndApply(1000, 100);
  1867. leveldb::BM_LogAndApply(1000, 10000);
  1868. leveldb::BM_LogAndApply(100, 100000);
  1869. return 0;
  1870. }
  1871. return leveldb::test::RunAllTests();
  1872. }