提供基本的ttl测试用例
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

1211 lignes
35 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 "db/db_impl.h"
  6. #include "db/filename.h"
  7. #include "db/version_set.h"
  8. #include "db/write_batch_internal.h"
  9. #include "leveldb/env.h"
  10. #include "leveldb/table.h"
  11. #include "util/logging.h"
  12. #include "util/testharness.h"
  13. #include "util/testutil.h"
  14. namespace leveldb {
  15. static std::string RandomString(Random* rnd, int len) {
  16. std::string r;
  17. test::RandomString(rnd, len, &r);
  18. return r;
  19. }
  20. class DBTest {
  21. public:
  22. std::string dbname_;
  23. Env* env_;
  24. DB* db_;
  25. Options last_options_;
  26. DBTest() : env_(Env::Default()) {
  27. dbname_ = test::TmpDir() + "/db_test";
  28. DestroyDB(dbname_, Options());
  29. db_ = NULL;
  30. Reopen();
  31. }
  32. ~DBTest() {
  33. delete db_;
  34. DestroyDB(dbname_, Options());
  35. }
  36. DBImpl* dbfull() {
  37. return reinterpret_cast<DBImpl*>(db_);
  38. }
  39. void Reopen(Options* options = NULL) {
  40. ASSERT_OK(TryReopen(options));
  41. }
  42. void DestroyAndReopen(Options* options = NULL) {
  43. delete db_;
  44. db_ = NULL;
  45. DestroyDB(dbname_, Options());
  46. ASSERT_OK(TryReopen(options));
  47. }
  48. Status TryReopen(Options* options) {
  49. delete db_;
  50. db_ = NULL;
  51. Options opts;
  52. if (options != NULL) {
  53. opts = *options;
  54. } else {
  55. opts.create_if_missing = true;
  56. }
  57. last_options_ = opts;
  58. return DB::Open(opts, dbname_, &db_);
  59. }
  60. Status Put(const std::string& k, const std::string& v) {
  61. return db_->Put(WriteOptions(), k, v);
  62. }
  63. Status Delete(const std::string& k) {
  64. return db_->Delete(WriteOptions(), k);
  65. }
  66. std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {
  67. ReadOptions options;
  68. options.snapshot = snapshot;
  69. std::string result;
  70. Status s = db_->Get(options, k, &result);
  71. if (s.IsNotFound()) {
  72. result = "NOT_FOUND";
  73. } else if (!s.ok()) {
  74. result = s.ToString();
  75. }
  76. return result;
  77. }
  78. std::string AllEntriesFor(const Slice& user_key) {
  79. Iterator* iter = dbfull()->TEST_NewInternalIterator();
  80. InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);
  81. iter->Seek(target.Encode());
  82. std::string result;
  83. if (!iter->status().ok()) {
  84. result = iter->status().ToString();
  85. } else {
  86. result = "[ ";
  87. bool first = true;
  88. while (iter->Valid()) {
  89. ParsedInternalKey ikey;
  90. if (!ParseInternalKey(iter->key(), &ikey)) {
  91. result += "CORRUPTED";
  92. } else {
  93. if (last_options_.comparator->Compare(
  94. ikey.user_key, user_key) != 0) {
  95. break;
  96. }
  97. if (!first) {
  98. result += ", ";
  99. }
  100. first = false;
  101. switch (ikey.type) {
  102. case kTypeValue:
  103. result += iter->value().ToString();
  104. break;
  105. case kTypeLargeValueRef:
  106. result += "LARGEVALUE(" + EscapeString(iter->value()) + ")";
  107. break;
  108. case kTypeDeletion:
  109. result += "DEL";
  110. break;
  111. }
  112. }
  113. iter->Next();
  114. }
  115. if (!first) {
  116. result += " ";
  117. }
  118. result += "]";
  119. }
  120. delete iter;
  121. return result;
  122. }
  123. int NumTableFilesAtLevel(int level) {
  124. std::string property;
  125. ASSERT_TRUE(
  126. db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level),
  127. &property));
  128. return atoi(property.c_str());
  129. }
  130. uint64_t Size(const Slice& start, const Slice& limit) {
  131. Range r(start, limit);
  132. uint64_t size;
  133. db_->GetApproximateSizes(&r, 1, &size);
  134. return size;
  135. }
  136. std::set<LargeValueRef> LargeValueFiles() const {
  137. // Return the set of large value files that exist in the database
  138. std::vector<std::string> filenames;
  139. env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose
  140. uint64_t number;
  141. LargeValueRef large_ref;
  142. FileType type;
  143. std::set<LargeValueRef> live;
  144. for (int i = 0; i < filenames.size(); i++) {
  145. if (ParseFileName(filenames[i], &number, &large_ref, &type) &&
  146. type == kLargeValueFile) {
  147. fprintf(stderr, " live: %s\n",
  148. LargeValueRefToFilenameString(large_ref).c_str());
  149. live.insert(large_ref);
  150. }
  151. }
  152. fprintf(stderr, "Found %d live large value files\n", (int)live.size());
  153. return live;
  154. }
  155. void Compact(const Slice& start, const Slice& limit) {
  156. dbfull()->TEST_CompactMemTable();
  157. int max_level_with_files = 1;
  158. for (int level = 1; level < config::kNumLevels; level++) {
  159. if (NumTableFilesAtLevel(level) > 0) {
  160. max_level_with_files = level;
  161. }
  162. }
  163. for (int level = 0; level < max_level_with_files; level++) {
  164. dbfull()->TEST_CompactRange(level, "", "~");
  165. }
  166. }
  167. void DumpFileCounts(const char* label) {
  168. fprintf(stderr, "---\n%s:\n", label);
  169. fprintf(stderr, "maxoverlap: %lld\n",
  170. static_cast<long long>(
  171. dbfull()->TEST_MaxNextLevelOverlappingBytes()));
  172. for (int level = 0; level < config::kNumLevels; level++) {
  173. int num = NumTableFilesAtLevel(level);
  174. if (num > 0) {
  175. fprintf(stderr, " level %3d : %d files\n", level, num);
  176. }
  177. }
  178. }
  179. std::string IterStatus(Iterator* iter) {
  180. std::string result;
  181. if (iter->Valid()) {
  182. result = iter->key().ToString() + "->" + iter->value().ToString();
  183. } else {
  184. result = "(invalid)";
  185. }
  186. return result;
  187. }
  188. };
  189. TEST(DBTest, Empty) {
  190. ASSERT_TRUE(db_ != NULL);
  191. ASSERT_EQ("NOT_FOUND", Get("foo"));
  192. }
  193. TEST(DBTest, ReadWrite) {
  194. ASSERT_OK(Put("foo", "v1"));
  195. ASSERT_EQ("v1", Get("foo"));
  196. ASSERT_OK(Put("bar", "v2"));
  197. ASSERT_OK(Put("foo", "v3"));
  198. ASSERT_EQ("v3", Get("foo"));
  199. ASSERT_EQ("v2", Get("bar"));
  200. }
  201. TEST(DBTest, PutDeleteGet) {
  202. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
  203. ASSERT_EQ("v1", Get("foo"));
  204. ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
  205. ASSERT_EQ("v2", Get("foo"));
  206. ASSERT_OK(db_->Delete(WriteOptions(), "foo"));
  207. ASSERT_EQ("NOT_FOUND", Get("foo"));
  208. }
  209. TEST(DBTest, IterEmpty) {
  210. Iterator* iter = db_->NewIterator(ReadOptions());
  211. iter->SeekToFirst();
  212. ASSERT_EQ(IterStatus(iter), "(invalid)");
  213. iter->SeekToLast();
  214. ASSERT_EQ(IterStatus(iter), "(invalid)");
  215. iter->Seek("foo");
  216. ASSERT_EQ(IterStatus(iter), "(invalid)");
  217. delete iter;
  218. }
  219. TEST(DBTest, IterSingle) {
  220. ASSERT_OK(Put("a", "va"));
  221. Iterator* iter = db_->NewIterator(ReadOptions());
  222. iter->SeekToFirst();
  223. ASSERT_EQ(IterStatus(iter), "a->va");
  224. iter->Next();
  225. ASSERT_EQ(IterStatus(iter), "(invalid)");
  226. iter->SeekToFirst();
  227. ASSERT_EQ(IterStatus(iter), "a->va");
  228. iter->Prev();
  229. ASSERT_EQ(IterStatus(iter), "(invalid)");
  230. iter->SeekToLast();
  231. ASSERT_EQ(IterStatus(iter), "a->va");
  232. iter->Next();
  233. ASSERT_EQ(IterStatus(iter), "(invalid)");
  234. iter->SeekToLast();
  235. ASSERT_EQ(IterStatus(iter), "a->va");
  236. iter->Prev();
  237. ASSERT_EQ(IterStatus(iter), "(invalid)");
  238. iter->Seek("");
  239. ASSERT_EQ(IterStatus(iter), "a->va");
  240. iter->Next();
  241. ASSERT_EQ(IterStatus(iter), "(invalid)");
  242. iter->Seek("a");
  243. ASSERT_EQ(IterStatus(iter), "a->va");
  244. iter->Next();
  245. ASSERT_EQ(IterStatus(iter), "(invalid)");
  246. iter->Seek("b");
  247. ASSERT_EQ(IterStatus(iter), "(invalid)");
  248. delete iter;
  249. }
  250. TEST(DBTest, IterMulti) {
  251. ASSERT_OK(Put("a", "va"));
  252. ASSERT_OK(Put("b", "vb"));
  253. ASSERT_OK(Put("c", "vc"));
  254. Iterator* iter = db_->NewIterator(ReadOptions());
  255. iter->SeekToFirst();
  256. ASSERT_EQ(IterStatus(iter), "a->va");
  257. iter->Next();
  258. ASSERT_EQ(IterStatus(iter), "b->vb");
  259. iter->Next();
  260. ASSERT_EQ(IterStatus(iter), "c->vc");
  261. iter->Next();
  262. ASSERT_EQ(IterStatus(iter), "(invalid)");
  263. iter->SeekToFirst();
  264. ASSERT_EQ(IterStatus(iter), "a->va");
  265. iter->Prev();
  266. ASSERT_EQ(IterStatus(iter), "(invalid)");
  267. iter->SeekToLast();
  268. ASSERT_EQ(IterStatus(iter), "c->vc");
  269. iter->Prev();
  270. ASSERT_EQ(IterStatus(iter), "b->vb");
  271. iter->Prev();
  272. ASSERT_EQ(IterStatus(iter), "a->va");
  273. iter->Prev();
  274. ASSERT_EQ(IterStatus(iter), "(invalid)");
  275. iter->SeekToLast();
  276. ASSERT_EQ(IterStatus(iter), "c->vc");
  277. iter->Next();
  278. ASSERT_EQ(IterStatus(iter), "(invalid)");
  279. iter->Seek("");
  280. ASSERT_EQ(IterStatus(iter), "a->va");
  281. iter->Seek("a");
  282. ASSERT_EQ(IterStatus(iter), "a->va");
  283. iter->Seek("ax");
  284. ASSERT_EQ(IterStatus(iter), "b->vb");
  285. iter->Seek("b");
  286. ASSERT_EQ(IterStatus(iter), "b->vb");
  287. iter->Seek("z");
  288. ASSERT_EQ(IterStatus(iter), "(invalid)");
  289. // Switch from reverse to forward
  290. iter->SeekToLast();
  291. iter->Prev();
  292. iter->Prev();
  293. iter->Next();
  294. ASSERT_EQ(IterStatus(iter), "b->vb");
  295. // Switch from forward to reverse
  296. iter->SeekToFirst();
  297. iter->Next();
  298. iter->Next();
  299. iter->Prev();
  300. ASSERT_EQ(IterStatus(iter), "b->vb");
  301. // Make sure iter stays at snapshot
  302. ASSERT_OK(Put("a", "va2"));
  303. ASSERT_OK(Put("a2", "va3"));
  304. ASSERT_OK(Put("b", "vb2"));
  305. ASSERT_OK(Put("c", "vc2"));
  306. ASSERT_OK(Delete("b"));
  307. iter->SeekToFirst();
  308. ASSERT_EQ(IterStatus(iter), "a->va");
  309. iter->Next();
  310. ASSERT_EQ(IterStatus(iter), "b->vb");
  311. iter->Next();
  312. ASSERT_EQ(IterStatus(iter), "c->vc");
  313. iter->Next();
  314. ASSERT_EQ(IterStatus(iter), "(invalid)");
  315. iter->SeekToLast();
  316. ASSERT_EQ(IterStatus(iter), "c->vc");
  317. iter->Prev();
  318. ASSERT_EQ(IterStatus(iter), "b->vb");
  319. iter->Prev();
  320. ASSERT_EQ(IterStatus(iter), "a->va");
  321. iter->Prev();
  322. ASSERT_EQ(IterStatus(iter), "(invalid)");
  323. delete iter;
  324. }
  325. TEST(DBTest, IterSmallAndLargeMix) {
  326. ASSERT_OK(Put("a", "va"));
  327. ASSERT_OK(Put("b", std::string(100000, 'b')));
  328. ASSERT_OK(Put("c", "vc"));
  329. ASSERT_OK(Put("d", std::string(100000, 'd')));
  330. ASSERT_OK(Put("e", std::string(100000, 'e')));
  331. Iterator* iter = db_->NewIterator(ReadOptions());
  332. iter->SeekToFirst();
  333. ASSERT_EQ(IterStatus(iter), "a->va");
  334. iter->Next();
  335. ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
  336. iter->Next();
  337. ASSERT_EQ(IterStatus(iter), "c->vc");
  338. iter->Next();
  339. ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
  340. iter->Next();
  341. ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
  342. iter->Next();
  343. ASSERT_EQ(IterStatus(iter), "(invalid)");
  344. iter->SeekToLast();
  345. ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
  346. iter->Prev();
  347. ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
  348. iter->Prev();
  349. ASSERT_EQ(IterStatus(iter), "c->vc");
  350. iter->Prev();
  351. ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
  352. iter->Prev();
  353. ASSERT_EQ(IterStatus(iter), "a->va");
  354. iter->Prev();
  355. ASSERT_EQ(IterStatus(iter), "(invalid)");
  356. delete iter;
  357. }
  358. TEST(DBTest, Recover) {
  359. ASSERT_OK(Put("foo", "v1"));
  360. ASSERT_OK(Put("baz", "v5"));
  361. Reopen();
  362. ASSERT_EQ("v1", Get("foo"));
  363. ASSERT_EQ("v1", Get("foo"));
  364. ASSERT_EQ("v5", Get("baz"));
  365. ASSERT_OK(Put("bar", "v2"));
  366. ASSERT_OK(Put("foo", "v3"));
  367. Reopen();
  368. ASSERT_EQ("v3", Get("foo"));
  369. ASSERT_OK(Put("foo", "v4"));
  370. ASSERT_EQ("v4", Get("foo"));
  371. ASSERT_EQ("v2", Get("bar"));
  372. ASSERT_EQ("v5", Get("baz"));
  373. }
  374. TEST(DBTest, RecoveryWithEmptyLog) {
  375. ASSERT_OK(Put("foo", "v1"));
  376. ASSERT_OK(Put("foo", "v2"));
  377. Reopen();
  378. Reopen();
  379. ASSERT_OK(Put("foo", "v3"));
  380. Reopen();
  381. ASSERT_EQ("v3", Get("foo"));
  382. }
  383. static std::string Key(int i) {
  384. char buf[100];
  385. snprintf(buf, sizeof(buf), "key%06d", i);
  386. return std::string(buf);
  387. }
  388. TEST(DBTest, MinorCompactionsHappen) {
  389. Options options;
  390. options.write_buffer_size = 10000;
  391. Reopen(&options);
  392. const int N = 500;
  393. int starting_num_tables = NumTableFilesAtLevel(0);
  394. for (int i = 0; i < N; i++) {
  395. ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
  396. }
  397. int ending_num_tables = NumTableFilesAtLevel(0);
  398. ASSERT_GT(ending_num_tables, starting_num_tables);
  399. for (int i = 0; i < N; i++) {
  400. ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
  401. }
  402. Reopen();
  403. for (int i = 0; i < N; i++) {
  404. ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
  405. }
  406. }
  407. TEST(DBTest, RecoverWithLargeLog) {
  408. {
  409. Options options;
  410. options.large_value_threshold = 1048576;
  411. Reopen(&options);
  412. ASSERT_OK(Put("big1", std::string(200000, '1')));
  413. ASSERT_OK(Put("big2", std::string(200000, '2')));
  414. ASSERT_OK(Put("small3", std::string(10, '3')));
  415. ASSERT_OK(Put("small4", std::string(10, '4')));
  416. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  417. }
  418. // Make sure that if we re-open with a small write buffer size that
  419. // we flush table files in the middle of a large log file.
  420. Options options;
  421. options.write_buffer_size = 100000;
  422. options.large_value_threshold = 1048576;
  423. Reopen(&options);
  424. ASSERT_EQ(NumTableFilesAtLevel(0), 3);
  425. ASSERT_EQ(std::string(200000, '1'), Get("big1"));
  426. ASSERT_EQ(std::string(200000, '2'), Get("big2"));
  427. ASSERT_EQ(std::string(10, '3'), Get("small3"));
  428. ASSERT_EQ(std::string(10, '4'), Get("small4"));
  429. ASSERT_GT(NumTableFilesAtLevel(0), 1);
  430. }
  431. TEST(DBTest, CompactionsGenerateMultipleFiles) {
  432. Options options;
  433. options.write_buffer_size = 100000000; // Large write buffer
  434. options.large_value_threshold = 1048576;
  435. Reopen(&options);
  436. Random rnd(301);
  437. // Write 8MB (80 values, each 100K)
  438. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  439. std::vector<std::string> values;
  440. for (int i = 0; i < 80; i++) {
  441. values.push_back(RandomString(&rnd, 100000));
  442. ASSERT_OK(Put(Key(i), values[i]));
  443. }
  444. // Reopening moves updates to level-0
  445. Reopen(&options);
  446. dbfull()->TEST_CompactRange(0, "", Key(100000));
  447. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  448. ASSERT_GT(NumTableFilesAtLevel(1), 1);
  449. for (int i = 0; i < 80; i++) {
  450. ASSERT_EQ(Get(Key(i)), values[i]);
  451. }
  452. }
  453. TEST(DBTest, SparseMerge) {
  454. Options options;
  455. options.compression = kNoCompression;
  456. Reopen(&options);
  457. // Suppose there is:
  458. // small amount of data with prefix A
  459. // large amount of data with prefix B
  460. // small amount of data with prefix C
  461. // and that recent updates have made small changes to all three prefixes.
  462. // Check that we do not do a compaction that merges all of B in one shot.
  463. const std::string value(1000, 'x');
  464. Put("A", "va");
  465. // Write approximately 100MB of "B" values
  466. for (int i = 0; i < 100000; i++) {
  467. char key[100];
  468. snprintf(key, sizeof(key), "B%010d", i);
  469. Put(key, value);
  470. }
  471. Put("C", "vc");
  472. Compact("", "z");
  473. // Make sparse update
  474. Put("A", "va2");
  475. Put("B100", "bvalue2");
  476. Put("C", "vc2");
  477. dbfull()->TEST_CompactMemTable();
  478. // Compactions should not cause us to create a situation where
  479. // a file overlaps too much data at the next level.
  480. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  481. dbfull()->TEST_CompactRange(0, "", "z");
  482. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  483. dbfull()->TEST_CompactRange(1, "", "z");
  484. ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
  485. }
  486. static bool Between(uint64_t val, uint64_t low, uint64_t high) {
  487. bool result = (val >= low) && (val <= high);
  488. if (!result) {
  489. fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
  490. (unsigned long long)(val),
  491. (unsigned long long)(low),
  492. (unsigned long long)(high));
  493. }
  494. return result;
  495. }
  496. TEST(DBTest, ApproximateSizes) {
  497. for (int test = 0; test < 2; test++) {
  498. // test==0: default large_value_threshold
  499. // test==1: 1 MB large_value_threshold
  500. Options options;
  501. options.large_value_threshold = (test == 0) ? 65536 : 1048576;
  502. options.write_buffer_size = 100000000; // Large write buffer
  503. options.compression = kNoCompression;
  504. DestroyAndReopen();
  505. ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
  506. Reopen(&options);
  507. ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
  508. // Write 8MB (80 values, each 100K)
  509. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  510. const int N = 80;
  511. Random rnd(301);
  512. for (int i = 0; i < N; i++) {
  513. ASSERT_OK(Put(Key(i), RandomString(&rnd, 100000)));
  514. }
  515. if (test == 1) {
  516. // 0 because GetApproximateSizes() does not account for memtable space for
  517. // non-large values
  518. ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
  519. } else {
  520. ASSERT_TRUE(Between(Size("", Key(50)), 100000*50, 100000*50 + 10000));
  521. ASSERT_TRUE(Between(Size(Key(20), Key(30)),
  522. 100000*10, 100000*10 + 10000));
  523. }
  524. // Check sizes across recovery by reopening a few times
  525. for (int run = 0; run < 3; run++) {
  526. Reopen(&options);
  527. for (int compact_start = 0; compact_start < N; compact_start += 10) {
  528. for (int i = 0; i < N; i += 10) {
  529. ASSERT_TRUE(Between(Size("", Key(i)), 100000*i, 100000*i + 10000));
  530. ASSERT_TRUE(Between(Size("", Key(i)+".suffix"),
  531. 100000 * (i+1), 100000 * (i+1) + 10000));
  532. ASSERT_TRUE(Between(Size(Key(i), Key(i+10)),
  533. 100000 * 10, 100000 * 10 + 10000));
  534. }
  535. ASSERT_TRUE(Between(Size("", Key(50)), 5000000, 5010000));
  536. ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), 5100000, 5110000));
  537. dbfull()->TEST_CompactRange(0,
  538. Key(compact_start),
  539. Key(compact_start + 9));
  540. }
  541. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  542. ASSERT_GT(NumTableFilesAtLevel(1), 0);
  543. }
  544. }
  545. }
  546. TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
  547. Options options;
  548. options.large_value_threshold = 65536;
  549. options.compression = kNoCompression;
  550. Reopen();
  551. Random rnd(301);
  552. std::string big1 = RandomString(&rnd, 100000);
  553. ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));
  554. ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));
  555. ASSERT_OK(Put(Key(2), big1));
  556. ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));
  557. ASSERT_OK(Put(Key(4), big1));
  558. ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));
  559. ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
  560. ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
  561. // Check sizes across recovery by reopening a few times
  562. for (int run = 0; run < 3; run++) {
  563. Reopen(&options);
  564. ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));
  565. ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));
  566. ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));
  567. ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));
  568. ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));
  569. ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));
  570. ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));
  571. ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));
  572. ASSERT_TRUE(Between(Size("", Key(8)), 550000, 551000));
  573. ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));
  574. dbfull()->TEST_CompactRange(0, Key(0), Key(100));
  575. }
  576. }
  577. TEST(DBTest, IteratorPinsRef) {
  578. Put("foo", "hello");
  579. // Get iterator that will yield the current contents of the DB.
  580. Iterator* iter = db_->NewIterator(ReadOptions());
  581. // Write to force compactions
  582. Put("foo", "newvalue1");
  583. for (int i = 0; i < 100; i++) {
  584. ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
  585. }
  586. Put("foo", "newvalue2");
  587. iter->SeekToFirst();
  588. ASSERT_TRUE(iter->Valid());
  589. ASSERT_EQ("foo", iter->key().ToString());
  590. ASSERT_EQ("hello", iter->value().ToString());
  591. iter->Next();
  592. ASSERT_TRUE(!iter->Valid());
  593. delete iter;
  594. }
  595. TEST(DBTest, Snapshot) {
  596. Put("foo", "v1");
  597. const Snapshot* s1 = db_->GetSnapshot();
  598. Put("foo", "v2");
  599. const Snapshot* s2 = db_->GetSnapshot();
  600. Put("foo", "v3");
  601. const Snapshot* s3 = db_->GetSnapshot();
  602. Put("foo", "v4");
  603. ASSERT_EQ("v1", Get("foo", s1));
  604. ASSERT_EQ("v2", Get("foo", s2));
  605. ASSERT_EQ("v3", Get("foo", s3));
  606. ASSERT_EQ("v4", Get("foo"));
  607. db_->ReleaseSnapshot(s3);
  608. ASSERT_EQ("v1", Get("foo", s1));
  609. ASSERT_EQ("v2", Get("foo", s2));
  610. ASSERT_EQ("v4", Get("foo"));
  611. db_->ReleaseSnapshot(s1);
  612. ASSERT_EQ("v2", Get("foo", s2));
  613. ASSERT_EQ("v4", Get("foo"));
  614. db_->ReleaseSnapshot(s2);
  615. ASSERT_EQ("v4", Get("foo"));
  616. }
  617. TEST(DBTest, HiddenValuesAreRemoved) {
  618. Random rnd(301);
  619. std::string big = RandomString(&rnd, 50000);
  620. Put("foo", big);
  621. Put("pastfoo", "v");
  622. const Snapshot* snapshot = db_->GetSnapshot();
  623. Put("foo", "tiny");
  624. Put("pastfoo2", "v2"); // Advance sequence number one more
  625. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  626. ASSERT_GT(NumTableFilesAtLevel(0), 0);
  627. ASSERT_EQ(big, Get("foo", snapshot));
  628. ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));
  629. db_->ReleaseSnapshot(snapshot);
  630. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");
  631. dbfull()->TEST_CompactRange(0, "", "x");
  632. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
  633. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  634. ASSERT_GE(NumTableFilesAtLevel(1), 1);
  635. dbfull()->TEST_CompactRange(1, "", "x");
  636. ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
  637. ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));
  638. }
  639. TEST(DBTest, DeletionMarkers1) {
  640. Put("foo", "v1");
  641. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  642. dbfull()->TEST_CompactRange(0, "", "z");
  643. dbfull()->TEST_CompactRange(1, "", "z");
  644. ASSERT_EQ(NumTableFilesAtLevel(2), 1); // foo => v1 is now in level 2 file
  645. Delete("foo");
  646. Put("foo", "v2");
  647. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
  648. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  649. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
  650. dbfull()->TEST_CompactRange(0, "", "z");
  651. // DEL eliminated, but v1 remains because we aren't compacting that level
  652. // (DEL can be eliminated because v2 hides v1).
  653. ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");
  654. dbfull()->TEST_CompactRange(1, "", "z");
  655. // Merging L1 w/ L2, so we are the base level for "foo", so DEL is removed.
  656. // (as is v1).
  657. ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");
  658. }
  659. TEST(DBTest, DeletionMarkers2) {
  660. Put("foo", "v1");
  661. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  662. dbfull()->TEST_CompactRange(0, "", "z");
  663. dbfull()->TEST_CompactRange(1, "", "z");
  664. ASSERT_EQ(NumTableFilesAtLevel(2), 1); // foo => v1 is now in level 2 file
  665. Delete("foo");
  666. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  667. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  668. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  669. dbfull()->TEST_CompactRange(0, "", "z");
  670. // DEL kept: L2 file overlaps
  671. ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
  672. dbfull()->TEST_CompactRange(1, "", "z");
  673. // Merging L1 w/ L2, so we are the base level for "foo", so DEL is removed.
  674. // (as is v1).
  675. ASSERT_EQ(AllEntriesFor("foo"), "[ ]");
  676. }
  677. TEST(DBTest, ComparatorCheck) {
  678. class NewComparator : public Comparator {
  679. public:
  680. virtual const char* Name() const { return "leveldb.NewComparator"; }
  681. virtual int Compare(const Slice& a, const Slice& b) const {
  682. return BytewiseComparator()->Compare(a, b);
  683. }
  684. virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
  685. BytewiseComparator()->FindShortestSeparator(s, l);
  686. }
  687. virtual void FindShortSuccessor(std::string* key) const {
  688. BytewiseComparator()->FindShortSuccessor(key);
  689. }
  690. };
  691. NewComparator cmp;
  692. Options new_options;
  693. new_options.comparator = &cmp;
  694. Status s = TryReopen(&new_options);
  695. ASSERT_TRUE(!s.ok());
  696. ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos)
  697. << s.ToString();
  698. }
  699. static bool LargeValuesOK(DBTest* db,
  700. const std::set<LargeValueRef>& expected) {
  701. std::set<LargeValueRef> actual = db->LargeValueFiles();
  702. if (actual.size() != expected.size()) {
  703. fprintf(stderr, "Sets differ in size: %d vs %d\n",
  704. (int)actual.size(), (int)expected.size());
  705. return false;
  706. }
  707. for (std::set<LargeValueRef>::const_iterator it = expected.begin();
  708. it != expected.end();
  709. ++it) {
  710. if (actual.count(*it) != 1) {
  711. fprintf(stderr, " key '%s' not found in actual set\n",
  712. LargeValueRefToFilenameString(*it).c_str());
  713. return false;
  714. }
  715. }
  716. return true;
  717. }
  718. TEST(DBTest, LargeValues1) {
  719. Options options;
  720. options.large_value_threshold = 10000;
  721. Reopen(&options);
  722. Random rnd(301);
  723. std::string big1;
  724. test::CompressibleString(&rnd, 1.0, 100000, &big1); // Not compressible
  725. std::set<LargeValueRef> expected;
  726. ASSERT_OK(Put("big1", big1));
  727. expected.insert(LargeValueRef::Make(big1, kNoCompression));
  728. ASSERT_TRUE(LargeValuesOK(this, expected));
  729. ASSERT_OK(Delete("big1"));
  730. ASSERT_TRUE(LargeValuesOK(this, expected));
  731. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  732. // No handling of deletion markers on memtable compactions, so big1 remains
  733. ASSERT_TRUE(LargeValuesOK(this, expected));
  734. dbfull()->TEST_CompactRange(0, "", "z");
  735. expected.erase(LargeValueRef::Make(big1, kNoCompression));
  736. ASSERT_TRUE(LargeValuesOK(this, expected));
  737. }
  738. static bool SnappyCompressionSupported() {
  739. std::string out;
  740. Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  741. return port::Snappy_Compress(in.data(), in.size(), &out);
  742. }
  743. TEST(DBTest, LargeValues2) {
  744. Options options;
  745. options.large_value_threshold = 10000;
  746. Reopen(&options);
  747. Random rnd(301);
  748. std::string big1, big2;
  749. test::CompressibleString(&rnd, 1.0, 20000, &big1); // Not compressible
  750. test::CompressibleString(&rnd, 0.6, 40000, &big2); // Compressible
  751. std::set<LargeValueRef> expected;
  752. ASSERT_TRUE(LargeValuesOK(this, expected));
  753. ASSERT_OK(Put("big1", big1));
  754. expected.insert(LargeValueRef::Make(big1, kNoCompression));
  755. ASSERT_EQ(big1, Get("big1"));
  756. ASSERT_TRUE(LargeValuesOK(this, expected));
  757. ASSERT_OK(Put("big2", big2));
  758. ASSERT_EQ(big2, Get("big2"));
  759. if (SnappyCompressionSupported()) {
  760. expected.insert(LargeValueRef::Make(big2, kSnappyCompression));
  761. } else {
  762. expected.insert(LargeValueRef::Make(big2, kNoCompression));
  763. }
  764. ASSERT_TRUE(LargeValuesOK(this, expected));
  765. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  766. ASSERT_TRUE(LargeValuesOK(this, expected));
  767. dbfull()->TEST_CompactRange(0, "", "z");
  768. ASSERT_TRUE(LargeValuesOK(this, expected));
  769. ASSERT_OK(Put("big2", big2));
  770. ASSERT_OK(Put("big2_b", big2));
  771. ASSERT_EQ(big1, Get("big1"));
  772. ASSERT_EQ(big2, Get("big2"));
  773. ASSERT_EQ(big2, Get("big2_b"));
  774. ASSERT_TRUE(LargeValuesOK(this, expected));
  775. ASSERT_OK(Delete("big1"));
  776. ASSERT_EQ("NOT_FOUND", Get("big1"));
  777. ASSERT_TRUE(LargeValuesOK(this, expected));
  778. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  779. ASSERT_TRUE(LargeValuesOK(this, expected));
  780. dbfull()->TEST_CompactRange(0, "", "z");
  781. expected.erase(LargeValueRef::Make(big1, kNoCompression));
  782. ASSERT_TRUE(LargeValuesOK(this, expected));
  783. dbfull()->TEST_CompactRange(1, "", "z");
  784. ASSERT_OK(Delete("big2"));
  785. ASSERT_EQ("NOT_FOUND", Get("big2"));
  786. ASSERT_EQ(big2, Get("big2_b"));
  787. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  788. ASSERT_TRUE(LargeValuesOK(this, expected));
  789. dbfull()->TEST_CompactRange(0, "", "z");
  790. ASSERT_TRUE(LargeValuesOK(this, expected));
  791. // Make sure the large value refs survive a reload and compactions after
  792. // the reload.
  793. Reopen();
  794. ASSERT_TRUE(LargeValuesOK(this, expected));
  795. ASSERT_OK(Put("foo", "bar"));
  796. ASSERT_OK(dbfull()->TEST_CompactMemTable());
  797. dbfull()->TEST_CompactRange(0, "", "z");
  798. ASSERT_TRUE(LargeValuesOK(this, expected));
  799. }
  800. TEST(DBTest, LargeValues3) {
  801. // Make sure we don't compress values if
  802. Options options;
  803. options.large_value_threshold = 10000;
  804. options.compression = kNoCompression;
  805. Reopen(&options);
  806. Random rnd(301);
  807. std::string big1 = std::string(100000, 'x'); // Very compressible
  808. std::set<LargeValueRef> expected;
  809. ASSERT_OK(Put("big1", big1));
  810. ASSERT_EQ(big1, Get("big1"));
  811. expected.insert(LargeValueRef::Make(big1, kNoCompression));
  812. ASSERT_TRUE(LargeValuesOK(this, expected));
  813. }
  814. TEST(DBTest, DBOpen_Options) {
  815. std::string dbname = test::TmpDir() + "/db_options_test";
  816. DestroyDB(dbname, Options());
  817. // Does not exist, and create_if_missing == false: error
  818. DB* db = NULL;
  819. Options opts;
  820. opts.create_if_missing = false;
  821. Status s = DB::Open(opts, dbname, &db);
  822. ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL);
  823. ASSERT_TRUE(db == NULL);
  824. // Does not exist, and create_if_missing == true: OK
  825. opts.create_if_missing = true;
  826. s = DB::Open(opts, dbname, &db);
  827. ASSERT_OK(s);
  828. ASSERT_TRUE(db != NULL);
  829. delete db;
  830. db = NULL;
  831. // Does exist, and error_if_exists == true: error
  832. opts.create_if_missing = false;
  833. opts.error_if_exists = true;
  834. s = DB::Open(opts, dbname, &db);
  835. ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL);
  836. ASSERT_TRUE(db == NULL);
  837. // Does exist, and error_if_exists == false: OK
  838. opts.create_if_missing = true;
  839. opts.error_if_exists = false;
  840. s = DB::Open(opts, dbname, &db);
  841. ASSERT_OK(s);
  842. ASSERT_TRUE(db != NULL);
  843. delete db;
  844. db = NULL;
  845. }
  846. class ModelDB: public DB {
  847. public:
  848. explicit ModelDB(const Options& options): options_(options) { }
  849. ~ModelDB() { }
  850. virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) {
  851. return DB::Put(o, k, v);
  852. }
  853. virtual Status Delete(const WriteOptions& o, const Slice& key) {
  854. return DB::Delete(o, key);
  855. }
  856. virtual Status Get(const ReadOptions& options,
  857. const Slice& key, std::string* value) {
  858. assert(false); // Not implemented
  859. return Status::NotFound(key);
  860. }
  861. virtual Iterator* NewIterator(const ReadOptions& options) {
  862. if (options.snapshot == NULL) {
  863. KVMap* saved = new KVMap;
  864. *saved = map_;
  865. return new ModelIter(saved, true);
  866. } else {
  867. const KVMap* snapshot_state =
  868. reinterpret_cast<const KVMap*>(options.snapshot->number_);
  869. return new ModelIter(snapshot_state, false);
  870. }
  871. }
  872. virtual const Snapshot* GetSnapshot() {
  873. KVMap* saved = new KVMap;
  874. *saved = map_;
  875. return snapshots_.New(
  876. reinterpret_cast<SequenceNumber>(saved));
  877. }
  878. virtual void ReleaseSnapshot(const Snapshot* snapshot) {
  879. const KVMap* saved = reinterpret_cast<const KVMap*>(snapshot->number_);
  880. delete saved;
  881. snapshots_.Delete(snapshot);
  882. }
  883. virtual Status Write(const WriteOptions& options, WriteBatch* batch) {
  884. assert(options.post_write_snapshot == NULL); // Not supported
  885. for (WriteBatchInternal::Iterator it(*batch); !it.Done(); it.Next()) {
  886. switch (it.op()) {
  887. case kTypeValue:
  888. map_[it.key().ToString()] = it.value().ToString();
  889. break;
  890. case kTypeLargeValueRef:
  891. assert(false); // Should not occur
  892. break;
  893. case kTypeDeletion:
  894. map_.erase(it.key().ToString());
  895. break;
  896. }
  897. }
  898. return Status::OK();
  899. }
  900. virtual bool GetProperty(const Slice& property, std::string* value) {
  901. return false;
  902. }
  903. virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) {
  904. for (int i = 0; i < n; i++) {
  905. sizes[i] = 0;
  906. }
  907. }
  908. private:
  909. typedef std::map<std::string, std::string> KVMap;
  910. class ModelIter: public Iterator {
  911. public:
  912. ModelIter(const KVMap* map, bool owned)
  913. : map_(map), owned_(owned), iter_(map_->end()) {
  914. }
  915. ~ModelIter() {
  916. if (owned_) delete map_;
  917. }
  918. virtual bool Valid() const { return iter_ != map_->end(); }
  919. virtual void SeekToFirst() { iter_ = map_->begin(); }
  920. virtual void SeekToLast() {
  921. if (map_->empty()) {
  922. iter_ = map_->end();
  923. } else {
  924. iter_ = map_->find(map_->rbegin()->first);
  925. }
  926. }
  927. virtual void Seek(const Slice& k) {
  928. iter_ = map_->lower_bound(k.ToString());
  929. }
  930. virtual void Next() { ++iter_; }
  931. virtual void Prev() { --iter_; }
  932. virtual Slice key() const { return iter_->first; }
  933. virtual Slice value() const { return iter_->second; }
  934. virtual Status status() const { return Status::OK(); }
  935. private:
  936. const KVMap* const map_;
  937. const bool owned_; // Do we own map_
  938. KVMap::const_iterator iter_;
  939. };
  940. const Options options_;
  941. KVMap map_;
  942. SnapshotList snapshots_;
  943. };
  944. static std::string RandomKey(Random* rnd) {
  945. int len = (rnd->OneIn(3)
  946. ? 1 // Short sometimes to encourage collisions
  947. : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));
  948. return test::RandomKey(rnd, len);
  949. }
  950. static bool CompareIterators(int step,
  951. DB* model,
  952. DB* db,
  953. const Snapshot* model_snap,
  954. const Snapshot* db_snap) {
  955. ReadOptions options;
  956. options.snapshot = model_snap;
  957. Iterator* miter = model->NewIterator(options);
  958. options.snapshot = db_snap;
  959. Iterator* dbiter = db->NewIterator(options);
  960. bool ok = true;
  961. int count = 0;
  962. for (miter->SeekToFirst(), dbiter->SeekToFirst();
  963. ok && miter->Valid() && dbiter->Valid();
  964. miter->Next(), dbiter->Next()) {
  965. count++;
  966. if (miter->key().compare(dbiter->key()) != 0) {
  967. fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n",
  968. step,
  969. EscapeString(miter->key()).c_str(),
  970. EscapeString(dbiter->key()).c_str());
  971. ok = false;
  972. break;
  973. }
  974. if (miter->value().compare(dbiter->value()) != 0) {
  975. fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
  976. step,
  977. EscapeString(miter->key()).c_str(),
  978. EscapeString(miter->value()).c_str(),
  979. EscapeString(miter->value()).c_str());
  980. ok = false;
  981. }
  982. }
  983. if (ok) {
  984. if (miter->Valid() != dbiter->Valid()) {
  985. fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
  986. step, miter->Valid(), dbiter->Valid());
  987. ok = false;
  988. }
  989. }
  990. fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
  991. delete miter;
  992. delete dbiter;
  993. return ok;
  994. }
  995. TEST(DBTest, Randomized) {
  996. Random rnd(test::RandomSeed());
  997. ModelDB model(last_options_);
  998. const int N = 10000;
  999. const Snapshot* model_snap = NULL;
  1000. const Snapshot* db_snap = NULL;
  1001. std::string k, v;
  1002. for (int step = 0; step < N; step++) {
  1003. if (step % 100 == 0) {
  1004. fprintf(stderr, "Step %d of %d\n", step, N);
  1005. }
  1006. int p = rnd.Uniform(100);
  1007. if (p < 45) { // Put
  1008. k = RandomKey(&rnd);
  1009. v = RandomString(&rnd,
  1010. rnd.OneIn(20)
  1011. ? 100 + rnd.Uniform(100)
  1012. : rnd.Uniform(8));
  1013. ASSERT_OK(model.Put(WriteOptions(), k, v));
  1014. ASSERT_OK(db_->Put(WriteOptions(), k, v));
  1015. } else if (p < 90) { // Delete
  1016. k = RandomKey(&rnd);
  1017. ASSERT_OK(model.Delete(WriteOptions(), k));
  1018. ASSERT_OK(db_->Delete(WriteOptions(), k));
  1019. } else { // Multi-element batch
  1020. WriteBatch b;
  1021. const int num = rnd.Uniform(8);
  1022. for (int i = 0; i < num; i++) {
  1023. if (i == 0 || !rnd.OneIn(10)) {
  1024. k = RandomKey(&rnd);
  1025. } else {
  1026. // Periodically re-use the same key from the previous iter, so
  1027. // we have multiple entries in the write batch for the same key
  1028. }
  1029. if (rnd.OneIn(2)) {
  1030. v = RandomString(&rnd, rnd.Uniform(10));
  1031. b.Put(k, v);
  1032. } else {
  1033. b.Delete(k);
  1034. }
  1035. }
  1036. ASSERT_OK(model.Write(WriteOptions(), &b));
  1037. ASSERT_OK(db_->Write(WriteOptions(), &b));
  1038. }
  1039. if ((step % 100) == 0) {
  1040. ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
  1041. ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));
  1042. // Save a snapshot from each DB this time that we'll use next
  1043. // time we compare things, to make sure the current state is
  1044. // preserved with the snapshot
  1045. if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
  1046. if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
  1047. Reopen();
  1048. ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
  1049. model_snap = model.GetSnapshot();
  1050. db_snap = db_->GetSnapshot();
  1051. }
  1052. }
  1053. if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
  1054. if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
  1055. }
  1056. }
  1057. int main(int argc, char** argv) {
  1058. return leveldb::test::RunAllTests();
  1059. }