write_batch_test.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include "rocksdb/db.h"
  10. #include <memory>
  11. #include "db/column_family.h"
  12. #include "db/memtable.h"
  13. #include "db/write_batch_internal.h"
  14. #include "rocksdb/env.h"
  15. #include "rocksdb/memtablerep.h"
  16. #include "rocksdb/utilities/write_batch_with_index.h"
  17. #include "rocksdb/write_buffer_manager.h"
  18. #include "table/scoped_arena_iterator.h"
  19. #include "test_util/testharness.h"
  20. #include "util/string_util.h"
  21. namespace ROCKSDB_NAMESPACE {
  22. static std::string PrintContents(WriteBatch* b) {
  23. InternalKeyComparator cmp(BytewiseComparator());
  24. auto factory = std::make_shared<SkipListFactory>();
  25. Options options;
  26. options.memtable_factory = factory;
  27. ImmutableCFOptions ioptions(options);
  28. WriteBufferManager wb(options.db_write_buffer_size);
  29. MemTable* mem = new MemTable(cmp, ioptions, MutableCFOptions(options), &wb,
  30. kMaxSequenceNumber, 0 /* column_family_id */);
  31. mem->Ref();
  32. std::string state;
  33. ColumnFamilyMemTablesDefault cf_mems_default(mem);
  34. Status s =
  35. WriteBatchInternal::InsertInto(b, &cf_mems_default, nullptr, nullptr);
  36. uint32_t count = 0;
  37. int put_count = 0;
  38. int delete_count = 0;
  39. int single_delete_count = 0;
  40. int delete_range_count = 0;
  41. int merge_count = 0;
  42. for (int i = 0; i < 2; ++i) {
  43. Arena arena;
  44. ScopedArenaIterator arena_iter_guard;
  45. std::unique_ptr<InternalIterator> iter_guard;
  46. InternalIterator* iter;
  47. if (i == 0) {
  48. iter = mem->NewIterator(ReadOptions(), &arena);
  49. arena_iter_guard.set(iter);
  50. } else {
  51. iter = mem->NewRangeTombstoneIterator(ReadOptions(),
  52. kMaxSequenceNumber /* read_seq */);
  53. iter_guard.reset(iter);
  54. }
  55. if (iter == nullptr) {
  56. continue;
  57. }
  58. for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  59. ParsedInternalKey ikey;
  60. ikey.clear();
  61. EXPECT_TRUE(ParseInternalKey(iter->key(), &ikey));
  62. switch (ikey.type) {
  63. case kTypeValue:
  64. state.append("Put(");
  65. state.append(ikey.user_key.ToString());
  66. state.append(", ");
  67. state.append(iter->value().ToString());
  68. state.append(")");
  69. count++;
  70. put_count++;
  71. break;
  72. case kTypeDeletion:
  73. state.append("Delete(");
  74. state.append(ikey.user_key.ToString());
  75. state.append(")");
  76. count++;
  77. delete_count++;
  78. break;
  79. case kTypeSingleDeletion:
  80. state.append("SingleDelete(");
  81. state.append(ikey.user_key.ToString());
  82. state.append(")");
  83. count++;
  84. single_delete_count++;
  85. break;
  86. case kTypeRangeDeletion:
  87. state.append("DeleteRange(");
  88. state.append(ikey.user_key.ToString());
  89. state.append(", ");
  90. state.append(iter->value().ToString());
  91. state.append(")");
  92. count++;
  93. delete_range_count++;
  94. break;
  95. case kTypeMerge:
  96. state.append("Merge(");
  97. state.append(ikey.user_key.ToString());
  98. state.append(", ");
  99. state.append(iter->value().ToString());
  100. state.append(")");
  101. count++;
  102. merge_count++;
  103. break;
  104. default:
  105. assert(false);
  106. break;
  107. }
  108. state.append("@");
  109. state.append(NumberToString(ikey.sequence));
  110. }
  111. }
  112. EXPECT_EQ(b->HasPut(), put_count > 0);
  113. EXPECT_EQ(b->HasDelete(), delete_count > 0);
  114. EXPECT_EQ(b->HasSingleDelete(), single_delete_count > 0);
  115. EXPECT_EQ(b->HasDeleteRange(), delete_range_count > 0);
  116. EXPECT_EQ(b->HasMerge(), merge_count > 0);
  117. if (!s.ok()) {
  118. state.append(s.ToString());
  119. } else if (count != WriteBatchInternal::Count(b)) {
  120. state.append("CountMismatch()");
  121. }
  122. delete mem->Unref();
  123. return state;
  124. }
  125. class WriteBatchTest : public testing::Test {};
  126. TEST_F(WriteBatchTest, Empty) {
  127. WriteBatch batch;
  128. ASSERT_EQ("", PrintContents(&batch));
  129. ASSERT_EQ(0u, WriteBatchInternal::Count(&batch));
  130. ASSERT_EQ(0u, batch.Count());
  131. }
  132. TEST_F(WriteBatchTest, Multiple) {
  133. WriteBatch batch;
  134. batch.Put(Slice("foo"), Slice("bar"));
  135. batch.Delete(Slice("box"));
  136. batch.DeleteRange(Slice("bar"), Slice("foo"));
  137. batch.Put(Slice("baz"), Slice("boo"));
  138. WriteBatchInternal::SetSequence(&batch, 100);
  139. ASSERT_EQ(100U, WriteBatchInternal::Sequence(&batch));
  140. ASSERT_EQ(4u, WriteBatchInternal::Count(&batch));
  141. ASSERT_EQ(
  142. "Put(baz, boo)@103"
  143. "Delete(box)@101"
  144. "Put(foo, bar)@100"
  145. "DeleteRange(bar, foo)@102",
  146. PrintContents(&batch));
  147. ASSERT_EQ(4u, batch.Count());
  148. }
  149. TEST_F(WriteBatchTest, Corruption) {
  150. WriteBatch batch;
  151. batch.Put(Slice("foo"), Slice("bar"));
  152. batch.Delete(Slice("box"));
  153. WriteBatchInternal::SetSequence(&batch, 200);
  154. Slice contents = WriteBatchInternal::Contents(&batch);
  155. WriteBatchInternal::SetContents(&batch,
  156. Slice(contents.data(),contents.size()-1));
  157. ASSERT_EQ("Put(foo, bar)@200"
  158. "Corruption: bad WriteBatch Delete",
  159. PrintContents(&batch));
  160. }
  161. TEST_F(WriteBatchTest, Append) {
  162. WriteBatch b1, b2;
  163. WriteBatchInternal::SetSequence(&b1, 200);
  164. WriteBatchInternal::SetSequence(&b2, 300);
  165. WriteBatchInternal::Append(&b1, &b2);
  166. ASSERT_EQ("",
  167. PrintContents(&b1));
  168. ASSERT_EQ(0u, b1.Count());
  169. b2.Put("a", "va");
  170. WriteBatchInternal::Append(&b1, &b2);
  171. ASSERT_EQ("Put(a, va)@200",
  172. PrintContents(&b1));
  173. ASSERT_EQ(1u, b1.Count());
  174. b2.Clear();
  175. b2.Put("b", "vb");
  176. WriteBatchInternal::Append(&b1, &b2);
  177. ASSERT_EQ("Put(a, va)@200"
  178. "Put(b, vb)@201",
  179. PrintContents(&b1));
  180. ASSERT_EQ(2u, b1.Count());
  181. b2.Delete("foo");
  182. WriteBatchInternal::Append(&b1, &b2);
  183. ASSERT_EQ("Put(a, va)@200"
  184. "Put(b, vb)@202"
  185. "Put(b, vb)@201"
  186. "Delete(foo)@203",
  187. PrintContents(&b1));
  188. ASSERT_EQ(4u, b1.Count());
  189. b2.Clear();
  190. b2.Put("c", "cc");
  191. b2.Put("d", "dd");
  192. b2.MarkWalTerminationPoint();
  193. b2.Put("e", "ee");
  194. WriteBatchInternal::Append(&b1, &b2, /*wal only*/ true);
  195. ASSERT_EQ(
  196. "Put(a, va)@200"
  197. "Put(b, vb)@202"
  198. "Put(b, vb)@201"
  199. "Put(c, cc)@204"
  200. "Put(d, dd)@205"
  201. "Delete(foo)@203",
  202. PrintContents(&b1));
  203. ASSERT_EQ(6u, b1.Count());
  204. ASSERT_EQ(
  205. "Put(c, cc)@0"
  206. "Put(d, dd)@1"
  207. "Put(e, ee)@2",
  208. PrintContents(&b2));
  209. ASSERT_EQ(3u, b2.Count());
  210. }
  211. TEST_F(WriteBatchTest, SingleDeletion) {
  212. WriteBatch batch;
  213. WriteBatchInternal::SetSequence(&batch, 100);
  214. ASSERT_EQ("", PrintContents(&batch));
  215. ASSERT_EQ(0u, batch.Count());
  216. batch.Put("a", "va");
  217. ASSERT_EQ("Put(a, va)@100", PrintContents(&batch));
  218. ASSERT_EQ(1u, batch.Count());
  219. batch.SingleDelete("a");
  220. ASSERT_EQ(
  221. "SingleDelete(a)@101"
  222. "Put(a, va)@100",
  223. PrintContents(&batch));
  224. ASSERT_EQ(2u, batch.Count());
  225. }
  226. namespace {
  227. struct TestHandler : public WriteBatch::Handler {
  228. std::string seen;
  229. Status PutCF(uint32_t column_family_id, const Slice& key,
  230. const Slice& value) override {
  231. if (column_family_id == 0) {
  232. seen += "Put(" + key.ToString() + ", " + value.ToString() + ")";
  233. } else {
  234. seen += "PutCF(" + ToString(column_family_id) + ", " +
  235. key.ToString() + ", " + value.ToString() + ")";
  236. }
  237. return Status::OK();
  238. }
  239. Status DeleteCF(uint32_t column_family_id, const Slice& key) override {
  240. if (column_family_id == 0) {
  241. seen += "Delete(" + key.ToString() + ")";
  242. } else {
  243. seen += "DeleteCF(" + ToString(column_family_id) + ", " +
  244. key.ToString() + ")";
  245. }
  246. return Status::OK();
  247. }
  248. Status SingleDeleteCF(uint32_t column_family_id,
  249. const Slice& key) override {
  250. if (column_family_id == 0) {
  251. seen += "SingleDelete(" + key.ToString() + ")";
  252. } else {
  253. seen += "SingleDeleteCF(" + ToString(column_family_id) + ", " +
  254. key.ToString() + ")";
  255. }
  256. return Status::OK();
  257. }
  258. Status DeleteRangeCF(uint32_t column_family_id, const Slice& begin_key,
  259. const Slice& end_key) override {
  260. if (column_family_id == 0) {
  261. seen += "DeleteRange(" + begin_key.ToString() + ", " +
  262. end_key.ToString() + ")";
  263. } else {
  264. seen += "DeleteRangeCF(" + ToString(column_family_id) + ", " +
  265. begin_key.ToString() + ", " + end_key.ToString() + ")";
  266. }
  267. return Status::OK();
  268. }
  269. Status MergeCF(uint32_t column_family_id, const Slice& key,
  270. const Slice& value) override {
  271. if (column_family_id == 0) {
  272. seen += "Merge(" + key.ToString() + ", " + value.ToString() + ")";
  273. } else {
  274. seen += "MergeCF(" + ToString(column_family_id) + ", " +
  275. key.ToString() + ", " + value.ToString() + ")";
  276. }
  277. return Status::OK();
  278. }
  279. void LogData(const Slice& blob) override {
  280. seen += "LogData(" + blob.ToString() + ")";
  281. }
  282. Status MarkBeginPrepare(bool unprepare) override {
  283. seen +=
  284. "MarkBeginPrepare(" + std::string(unprepare ? "true" : "false") + ")";
  285. return Status::OK();
  286. }
  287. Status MarkEndPrepare(const Slice& xid) override {
  288. seen += "MarkEndPrepare(" + xid.ToString() + ")";
  289. return Status::OK();
  290. }
  291. Status MarkNoop(bool empty_batch) override {
  292. seen += "MarkNoop(" + std::string(empty_batch ? "true" : "false") + ")";
  293. return Status::OK();
  294. }
  295. Status MarkCommit(const Slice& xid) override {
  296. seen += "MarkCommit(" + xid.ToString() + ")";
  297. return Status::OK();
  298. }
  299. Status MarkRollback(const Slice& xid) override {
  300. seen += "MarkRollback(" + xid.ToString() + ")";
  301. return Status::OK();
  302. }
  303. };
  304. }
  305. TEST_F(WriteBatchTest, PutNotImplemented) {
  306. WriteBatch batch;
  307. batch.Put(Slice("k1"), Slice("v1"));
  308. ASSERT_EQ(1u, batch.Count());
  309. ASSERT_EQ("Put(k1, v1)@0", PrintContents(&batch));
  310. WriteBatch::Handler handler;
  311. ASSERT_OK(batch.Iterate(&handler));
  312. }
  313. TEST_F(WriteBatchTest, DeleteNotImplemented) {
  314. WriteBatch batch;
  315. batch.Delete(Slice("k2"));
  316. ASSERT_EQ(1u, batch.Count());
  317. ASSERT_EQ("Delete(k2)@0", PrintContents(&batch));
  318. WriteBatch::Handler handler;
  319. ASSERT_OK(batch.Iterate(&handler));
  320. }
  321. TEST_F(WriteBatchTest, SingleDeleteNotImplemented) {
  322. WriteBatch batch;
  323. batch.SingleDelete(Slice("k2"));
  324. ASSERT_EQ(1u, batch.Count());
  325. ASSERT_EQ("SingleDelete(k2)@0", PrintContents(&batch));
  326. WriteBatch::Handler handler;
  327. ASSERT_OK(batch.Iterate(&handler));
  328. }
  329. TEST_F(WriteBatchTest, MergeNotImplemented) {
  330. WriteBatch batch;
  331. batch.Merge(Slice("foo"), Slice("bar"));
  332. ASSERT_EQ(1u, batch.Count());
  333. ASSERT_EQ("Merge(foo, bar)@0", PrintContents(&batch));
  334. WriteBatch::Handler handler;
  335. ASSERT_OK(batch.Iterate(&handler));
  336. }
  337. TEST_F(WriteBatchTest, Blob) {
  338. WriteBatch batch;
  339. batch.Put(Slice("k1"), Slice("v1"));
  340. batch.Put(Slice("k2"), Slice("v2"));
  341. batch.Put(Slice("k3"), Slice("v3"));
  342. batch.PutLogData(Slice("blob1"));
  343. batch.Delete(Slice("k2"));
  344. batch.SingleDelete(Slice("k3"));
  345. batch.PutLogData(Slice("blob2"));
  346. batch.Merge(Slice("foo"), Slice("bar"));
  347. ASSERT_EQ(6u, batch.Count());
  348. ASSERT_EQ(
  349. "Merge(foo, bar)@5"
  350. "Put(k1, v1)@0"
  351. "Delete(k2)@3"
  352. "Put(k2, v2)@1"
  353. "SingleDelete(k3)@4"
  354. "Put(k3, v3)@2",
  355. PrintContents(&batch));
  356. TestHandler handler;
  357. batch.Iterate(&handler);
  358. ASSERT_EQ(
  359. "Put(k1, v1)"
  360. "Put(k2, v2)"
  361. "Put(k3, v3)"
  362. "LogData(blob1)"
  363. "Delete(k2)"
  364. "SingleDelete(k3)"
  365. "LogData(blob2)"
  366. "Merge(foo, bar)",
  367. handler.seen);
  368. }
  369. TEST_F(WriteBatchTest, PrepareCommit) {
  370. WriteBatch batch;
  371. WriteBatchInternal::InsertNoop(&batch);
  372. batch.Put(Slice("k1"), Slice("v1"));
  373. batch.Put(Slice("k2"), Slice("v2"));
  374. batch.SetSavePoint();
  375. WriteBatchInternal::MarkEndPrepare(&batch, Slice("xid1"));
  376. Status s = batch.RollbackToSavePoint();
  377. ASSERT_EQ(s, Status::NotFound());
  378. WriteBatchInternal::MarkCommit(&batch, Slice("xid1"));
  379. WriteBatchInternal::MarkRollback(&batch, Slice("xid1"));
  380. ASSERT_EQ(2u, batch.Count());
  381. TestHandler handler;
  382. batch.Iterate(&handler);
  383. ASSERT_EQ(
  384. "MarkBeginPrepare(false)"
  385. "Put(k1, v1)"
  386. "Put(k2, v2)"
  387. "MarkEndPrepare(xid1)"
  388. "MarkCommit(xid1)"
  389. "MarkRollback(xid1)",
  390. handler.seen);
  391. }
  392. // It requires more than 30GB of memory to run the test. With single memory
  393. // allocation of more than 30GB.
  394. // Not all platform can run it. Also it runs a long time. So disable it.
  395. TEST_F(WriteBatchTest, DISABLED_ManyUpdates) {
  396. // Insert key and value of 3GB and push total batch size to 12GB.
  397. static const size_t kKeyValueSize = 4u;
  398. static const uint32_t kNumUpdates = uint32_t(3 << 30);
  399. std::string raw(kKeyValueSize, 'A');
  400. WriteBatch batch(kNumUpdates * (4 + kKeyValueSize * 2) + 1024u);
  401. char c = 'A';
  402. for (uint32_t i = 0; i < kNumUpdates; i++) {
  403. if (c > 'Z') {
  404. c = 'A';
  405. }
  406. raw[0] = c;
  407. raw[raw.length() - 1] = c;
  408. c++;
  409. batch.Put(raw, raw);
  410. }
  411. ASSERT_EQ(kNumUpdates, batch.Count());
  412. struct NoopHandler : public WriteBatch::Handler {
  413. uint32_t num_seen = 0;
  414. char expected_char = 'A';
  415. Status PutCF(uint32_t /*column_family_id*/, const Slice& key,
  416. const Slice& value) override {
  417. EXPECT_EQ(kKeyValueSize, key.size());
  418. EXPECT_EQ(kKeyValueSize, value.size());
  419. EXPECT_EQ(expected_char, key[0]);
  420. EXPECT_EQ(expected_char, value[0]);
  421. EXPECT_EQ(expected_char, key[kKeyValueSize - 1]);
  422. EXPECT_EQ(expected_char, value[kKeyValueSize - 1]);
  423. expected_char++;
  424. if (expected_char > 'Z') {
  425. expected_char = 'A';
  426. }
  427. ++num_seen;
  428. return Status::OK();
  429. }
  430. Status DeleteCF(uint32_t /*column_family_id*/,
  431. const Slice& /*key*/) override {
  432. ADD_FAILURE();
  433. return Status::OK();
  434. }
  435. Status SingleDeleteCF(uint32_t /*column_family_id*/,
  436. const Slice& /*key*/) override {
  437. ADD_FAILURE();
  438. return Status::OK();
  439. }
  440. Status MergeCF(uint32_t /*column_family_id*/, const Slice& /*key*/,
  441. const Slice& /*value*/) override {
  442. ADD_FAILURE();
  443. return Status::OK();
  444. }
  445. void LogData(const Slice& /*blob*/) override { ADD_FAILURE(); }
  446. bool Continue() override { return num_seen < kNumUpdates; }
  447. } handler;
  448. batch.Iterate(&handler);
  449. ASSERT_EQ(kNumUpdates, handler.num_seen);
  450. }
  451. // The test requires more than 18GB memory to run it, with single memory
  452. // allocation of more than 12GB. Not all the platform can run it. So disable it.
  453. TEST_F(WriteBatchTest, DISABLED_LargeKeyValue) {
  454. // Insert key and value of 3GB and push total batch size to 12GB.
  455. static const size_t kKeyValueSize = 3221225472u;
  456. std::string raw(kKeyValueSize, 'A');
  457. WriteBatch batch(size_t(12884901888ull + 1024u));
  458. for (char i = 0; i < 2; i++) {
  459. raw[0] = 'A' + i;
  460. raw[raw.length() - 1] = 'A' - i;
  461. batch.Put(raw, raw);
  462. }
  463. ASSERT_EQ(2u, batch.Count());
  464. struct NoopHandler : public WriteBatch::Handler {
  465. int num_seen = 0;
  466. Status PutCF(uint32_t /*column_family_id*/, const Slice& key,
  467. const Slice& value) override {
  468. EXPECT_EQ(kKeyValueSize, key.size());
  469. EXPECT_EQ(kKeyValueSize, value.size());
  470. EXPECT_EQ('A' + num_seen, key[0]);
  471. EXPECT_EQ('A' + num_seen, value[0]);
  472. EXPECT_EQ('A' - num_seen, key[kKeyValueSize - 1]);
  473. EXPECT_EQ('A' - num_seen, value[kKeyValueSize - 1]);
  474. ++num_seen;
  475. return Status::OK();
  476. }
  477. Status DeleteCF(uint32_t /*column_family_id*/,
  478. const Slice& /*key*/) override {
  479. ADD_FAILURE();
  480. return Status::OK();
  481. }
  482. Status SingleDeleteCF(uint32_t /*column_family_id*/,
  483. const Slice& /*key*/) override {
  484. ADD_FAILURE();
  485. return Status::OK();
  486. }
  487. Status MergeCF(uint32_t /*column_family_id*/, const Slice& /*key*/,
  488. const Slice& /*value*/) override {
  489. ADD_FAILURE();
  490. return Status::OK();
  491. }
  492. void LogData(const Slice& /*blob*/) override { ADD_FAILURE(); }
  493. bool Continue() override { return num_seen < 2; }
  494. } handler;
  495. batch.Iterate(&handler);
  496. ASSERT_EQ(2, handler.num_seen);
  497. }
  498. TEST_F(WriteBatchTest, Continue) {
  499. WriteBatch batch;
  500. struct Handler : public TestHandler {
  501. int num_seen = 0;
  502. Status PutCF(uint32_t column_family_id, const Slice& key,
  503. const Slice& value) override {
  504. ++num_seen;
  505. return TestHandler::PutCF(column_family_id, key, value);
  506. }
  507. Status DeleteCF(uint32_t column_family_id, const Slice& key) override {
  508. ++num_seen;
  509. return TestHandler::DeleteCF(column_family_id, key);
  510. }
  511. Status SingleDeleteCF(uint32_t column_family_id,
  512. const Slice& key) override {
  513. ++num_seen;
  514. return TestHandler::SingleDeleteCF(column_family_id, key);
  515. }
  516. Status MergeCF(uint32_t column_family_id, const Slice& key,
  517. const Slice& value) override {
  518. ++num_seen;
  519. return TestHandler::MergeCF(column_family_id, key, value);
  520. }
  521. void LogData(const Slice& blob) override {
  522. ++num_seen;
  523. TestHandler::LogData(blob);
  524. }
  525. bool Continue() override { return num_seen < 5; }
  526. } handler;
  527. batch.Put(Slice("k1"), Slice("v1"));
  528. batch.Put(Slice("k2"), Slice("v2"));
  529. batch.PutLogData(Slice("blob1"));
  530. batch.Delete(Slice("k1"));
  531. batch.SingleDelete(Slice("k2"));
  532. batch.PutLogData(Slice("blob2"));
  533. batch.Merge(Slice("foo"), Slice("bar"));
  534. batch.Iterate(&handler);
  535. ASSERT_EQ(
  536. "Put(k1, v1)"
  537. "Put(k2, v2)"
  538. "LogData(blob1)"
  539. "Delete(k1)"
  540. "SingleDelete(k2)",
  541. handler.seen);
  542. }
  543. TEST_F(WriteBatchTest, PutGatherSlices) {
  544. WriteBatch batch;
  545. batch.Put(Slice("foo"), Slice("bar"));
  546. {
  547. // Try a write where the key is one slice but the value is two
  548. Slice key_slice("baz");
  549. Slice value_slices[2] = { Slice("header"), Slice("payload") };
  550. batch.Put(SliceParts(&key_slice, 1),
  551. SliceParts(value_slices, 2));
  552. }
  553. {
  554. // One where the key is composite but the value is a single slice
  555. Slice key_slices[3] = { Slice("key"), Slice("part2"), Slice("part3") };
  556. Slice value_slice("value");
  557. batch.Put(SliceParts(key_slices, 3),
  558. SliceParts(&value_slice, 1));
  559. }
  560. WriteBatchInternal::SetSequence(&batch, 100);
  561. ASSERT_EQ("Put(baz, headerpayload)@101"
  562. "Put(foo, bar)@100"
  563. "Put(keypart2part3, value)@102",
  564. PrintContents(&batch));
  565. ASSERT_EQ(3u, batch.Count());
  566. }
  567. namespace {
  568. class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
  569. public:
  570. explicit ColumnFamilyHandleImplDummy(int id)
  571. : ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
  572. uint32_t GetID() const override { return id_; }
  573. const Comparator* GetComparator() const override {
  574. return BytewiseComparator();
  575. }
  576. private:
  577. uint32_t id_;
  578. };
  579. } // namespace anonymous
  580. TEST_F(WriteBatchTest, ColumnFamiliesBatchTest) {
  581. WriteBatch batch;
  582. ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
  583. batch.Put(&zero, Slice("foo"), Slice("bar"));
  584. batch.Put(&two, Slice("twofoo"), Slice("bar2"));
  585. batch.Put(&eight, Slice("eightfoo"), Slice("bar8"));
  586. batch.Delete(&eight, Slice("eightfoo"));
  587. batch.SingleDelete(&two, Slice("twofoo"));
  588. batch.DeleteRange(&two, Slice("3foo"), Slice("4foo"));
  589. batch.Merge(&three, Slice("threethree"), Slice("3three"));
  590. batch.Put(&zero, Slice("foo"), Slice("bar"));
  591. batch.Merge(Slice("omom"), Slice("nom"));
  592. TestHandler handler;
  593. batch.Iterate(&handler);
  594. ASSERT_EQ(
  595. "Put(foo, bar)"
  596. "PutCF(2, twofoo, bar2)"
  597. "PutCF(8, eightfoo, bar8)"
  598. "DeleteCF(8, eightfoo)"
  599. "SingleDeleteCF(2, twofoo)"
  600. "DeleteRangeCF(2, 3foo, 4foo)"
  601. "MergeCF(3, threethree, 3three)"
  602. "Put(foo, bar)"
  603. "Merge(omom, nom)",
  604. handler.seen);
  605. }
  606. #ifndef ROCKSDB_LITE
  607. TEST_F(WriteBatchTest, ColumnFamiliesBatchWithIndexTest) {
  608. WriteBatchWithIndex batch;
  609. ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
  610. batch.Put(&zero, Slice("foo"), Slice("bar"));
  611. batch.Put(&two, Slice("twofoo"), Slice("bar2"));
  612. batch.Put(&eight, Slice("eightfoo"), Slice("bar8"));
  613. batch.Delete(&eight, Slice("eightfoo"));
  614. batch.SingleDelete(&two, Slice("twofoo"));
  615. batch.Merge(&three, Slice("threethree"), Slice("3three"));
  616. batch.Put(&zero, Slice("foo"), Slice("bar"));
  617. batch.Merge(Slice("omom"), Slice("nom"));
  618. std::unique_ptr<WBWIIterator> iter;
  619. iter.reset(batch.NewIterator(&eight));
  620. iter->Seek("eightfoo");
  621. ASSERT_OK(iter->status());
  622. ASSERT_TRUE(iter->Valid());
  623. ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
  624. ASSERT_EQ("eightfoo", iter->Entry().key.ToString());
  625. ASSERT_EQ("bar8", iter->Entry().value.ToString());
  626. iter->Next();
  627. ASSERT_OK(iter->status());
  628. ASSERT_TRUE(iter->Valid());
  629. ASSERT_EQ(WriteType::kDeleteRecord, iter->Entry().type);
  630. ASSERT_EQ("eightfoo", iter->Entry().key.ToString());
  631. iter->Next();
  632. ASSERT_OK(iter->status());
  633. ASSERT_TRUE(!iter->Valid());
  634. iter.reset(batch.NewIterator(&two));
  635. iter->Seek("twofoo");
  636. ASSERT_OK(iter->status());
  637. ASSERT_TRUE(iter->Valid());
  638. ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
  639. ASSERT_EQ("twofoo", iter->Entry().key.ToString());
  640. ASSERT_EQ("bar2", iter->Entry().value.ToString());
  641. iter->Next();
  642. ASSERT_OK(iter->status());
  643. ASSERT_TRUE(iter->Valid());
  644. ASSERT_EQ(WriteType::kSingleDeleteRecord, iter->Entry().type);
  645. ASSERT_EQ("twofoo", iter->Entry().key.ToString());
  646. iter->Next();
  647. ASSERT_OK(iter->status());
  648. ASSERT_TRUE(!iter->Valid());
  649. iter.reset(batch.NewIterator());
  650. iter->Seek("gggg");
  651. ASSERT_OK(iter->status());
  652. ASSERT_TRUE(iter->Valid());
  653. ASSERT_EQ(WriteType::kMergeRecord, iter->Entry().type);
  654. ASSERT_EQ("omom", iter->Entry().key.ToString());
  655. ASSERT_EQ("nom", iter->Entry().value.ToString());
  656. iter->Next();
  657. ASSERT_OK(iter->status());
  658. ASSERT_TRUE(!iter->Valid());
  659. iter.reset(batch.NewIterator(&zero));
  660. iter->Seek("foo");
  661. ASSERT_OK(iter->status());
  662. ASSERT_TRUE(iter->Valid());
  663. ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
  664. ASSERT_EQ("foo", iter->Entry().key.ToString());
  665. ASSERT_EQ("bar", iter->Entry().value.ToString());
  666. iter->Next();
  667. ASSERT_OK(iter->status());
  668. ASSERT_TRUE(iter->Valid());
  669. ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
  670. ASSERT_EQ("foo", iter->Entry().key.ToString());
  671. ASSERT_EQ("bar", iter->Entry().value.ToString());
  672. iter->Next();
  673. ASSERT_OK(iter->status());
  674. ASSERT_TRUE(iter->Valid());
  675. ASSERT_EQ(WriteType::kMergeRecord, iter->Entry().type);
  676. ASSERT_EQ("omom", iter->Entry().key.ToString());
  677. ASSERT_EQ("nom", iter->Entry().value.ToString());
  678. iter->Next();
  679. ASSERT_OK(iter->status());
  680. ASSERT_TRUE(!iter->Valid());
  681. TestHandler handler;
  682. batch.GetWriteBatch()->Iterate(&handler);
  683. ASSERT_EQ(
  684. "Put(foo, bar)"
  685. "PutCF(2, twofoo, bar2)"
  686. "PutCF(8, eightfoo, bar8)"
  687. "DeleteCF(8, eightfoo)"
  688. "SingleDeleteCF(2, twofoo)"
  689. "MergeCF(3, threethree, 3three)"
  690. "Put(foo, bar)"
  691. "Merge(omom, nom)",
  692. handler.seen);
  693. }
  694. #endif // !ROCKSDB_LITE
  695. TEST_F(WriteBatchTest, SavePointTest) {
  696. Status s;
  697. WriteBatch batch;
  698. batch.SetSavePoint();
  699. batch.Put("A", "a");
  700. batch.Put("B", "b");
  701. batch.SetSavePoint();
  702. batch.Put("C", "c");
  703. batch.Delete("A");
  704. batch.SetSavePoint();
  705. batch.SetSavePoint();
  706. ASSERT_OK(batch.RollbackToSavePoint());
  707. ASSERT_EQ(
  708. "Delete(A)@3"
  709. "Put(A, a)@0"
  710. "Put(B, b)@1"
  711. "Put(C, c)@2",
  712. PrintContents(&batch));
  713. ASSERT_OK(batch.RollbackToSavePoint());
  714. ASSERT_OK(batch.RollbackToSavePoint());
  715. ASSERT_EQ(
  716. "Put(A, a)@0"
  717. "Put(B, b)@1",
  718. PrintContents(&batch));
  719. batch.Delete("A");
  720. batch.Put("B", "bb");
  721. ASSERT_OK(batch.RollbackToSavePoint());
  722. ASSERT_EQ("", PrintContents(&batch));
  723. s = batch.RollbackToSavePoint();
  724. ASSERT_TRUE(s.IsNotFound());
  725. ASSERT_EQ("", PrintContents(&batch));
  726. batch.Put("D", "d");
  727. batch.Delete("A");
  728. batch.SetSavePoint();
  729. batch.Put("A", "aaa");
  730. ASSERT_OK(batch.RollbackToSavePoint());
  731. ASSERT_EQ(
  732. "Delete(A)@1"
  733. "Put(D, d)@0",
  734. PrintContents(&batch));
  735. batch.SetSavePoint();
  736. batch.Put("D", "d");
  737. batch.Delete("A");
  738. ASSERT_OK(batch.RollbackToSavePoint());
  739. ASSERT_EQ(
  740. "Delete(A)@1"
  741. "Put(D, d)@0",
  742. PrintContents(&batch));
  743. s = batch.RollbackToSavePoint();
  744. ASSERT_TRUE(s.IsNotFound());
  745. ASSERT_EQ(
  746. "Delete(A)@1"
  747. "Put(D, d)@0",
  748. PrintContents(&batch));
  749. WriteBatch batch2;
  750. s = batch2.RollbackToSavePoint();
  751. ASSERT_TRUE(s.IsNotFound());
  752. ASSERT_EQ("", PrintContents(&batch2));
  753. batch2.Delete("A");
  754. batch2.SetSavePoint();
  755. s = batch2.RollbackToSavePoint();
  756. ASSERT_OK(s);
  757. ASSERT_EQ("Delete(A)@0", PrintContents(&batch2));
  758. batch2.Clear();
  759. ASSERT_EQ("", PrintContents(&batch2));
  760. batch2.SetSavePoint();
  761. batch2.Delete("B");
  762. ASSERT_EQ("Delete(B)@0", PrintContents(&batch2));
  763. batch2.SetSavePoint();
  764. s = batch2.RollbackToSavePoint();
  765. ASSERT_OK(s);
  766. ASSERT_EQ("Delete(B)@0", PrintContents(&batch2));
  767. s = batch2.RollbackToSavePoint();
  768. ASSERT_OK(s);
  769. ASSERT_EQ("", PrintContents(&batch2));
  770. s = batch2.RollbackToSavePoint();
  771. ASSERT_TRUE(s.IsNotFound());
  772. ASSERT_EQ("", PrintContents(&batch2));
  773. WriteBatch batch3;
  774. s = batch3.PopSavePoint();
  775. ASSERT_TRUE(s.IsNotFound());
  776. ASSERT_EQ("", PrintContents(&batch3));
  777. batch3.SetSavePoint();
  778. batch3.Delete("A");
  779. s = batch3.PopSavePoint();
  780. ASSERT_OK(s);
  781. ASSERT_EQ("Delete(A)@0", PrintContents(&batch3));
  782. }
  783. TEST_F(WriteBatchTest, MemoryLimitTest) {
  784. Status s;
  785. // The header size is 12 bytes. The two Puts take 8 bytes which gives total
  786. // of 12 + 8 * 2 = 28 bytes.
  787. WriteBatch batch(0, 28);
  788. ASSERT_OK(batch.Put("a", "...."));
  789. ASSERT_OK(batch.Put("b", "...."));
  790. s = batch.Put("c", "....");
  791. ASSERT_TRUE(s.IsMemoryLimit());
  792. }
  793. } // namespace ROCKSDB_NAMESPACE
  794. int main(int argc, char** argv) {
  795. ::testing::InitGoogleTest(&argc, argv);
  796. return RUN_ALL_TESTS();
  797. }