1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
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.
10 #include "rocksdb/db.h"
13 #include "db/column_family.h"
14 #include "db/memtable.h"
15 #include "db/write_batch_internal.h"
16 #include "rocksdb/env.h"
17 #include "rocksdb/memtablerep.h"
18 #include "rocksdb/utilities/write_batch_with_index.h"
19 #include "rocksdb/write_buffer_manager.h"
20 #include "table/scoped_arena_iterator.h"
21 #include "util/logging.h"
22 #include "util/string_util.h"
23 #include "util/testharness.h"
27 static std::string
PrintContents(WriteBatch
* b
) {
28 InternalKeyComparator
cmp(BytewiseComparator());
29 auto factory
= std::make_shared
<SkipListFactory
>();
31 options
.memtable_factory
= factory
;
32 ImmutableCFOptions
ioptions(options
);
33 WriteBufferManager
wb(options
.db_write_buffer_size
);
34 MemTable
* mem
= new MemTable(cmp
, ioptions
, MutableCFOptions(options
), &wb
,
38 ColumnFamilyMemTablesDefault
cf_mems_default(mem
);
39 Status s
= WriteBatchInternal::InsertInto(b
, &cf_mems_default
, nullptr);
43 int single_delete_count
= 0;
44 int delete_range_count
= 0;
46 for (int i
= 0; i
< 2; ++i
) {
48 ScopedArenaIterator arena_iter_guard
;
49 std::unique_ptr
<InternalIterator
> iter_guard
;
50 InternalIterator
* iter
;
52 iter
= mem
->NewIterator(ReadOptions(), &arena
);
53 arena_iter_guard
.set(iter
);
55 iter
= mem
->NewRangeTombstoneIterator(ReadOptions());
56 iter_guard
.reset(iter
);
58 if (iter
== nullptr) {
61 for (iter
->SeekToFirst(); iter
->Valid(); iter
->Next()) {
62 ParsedInternalKey ikey
;
63 memset((void*)&ikey
, 0, sizeof(ikey
));
64 EXPECT_TRUE(ParseInternalKey(iter
->key(), &ikey
));
68 state
.append(ikey
.user_key
.ToString());
70 state
.append(iter
->value().ToString());
76 state
.append("Delete(");
77 state
.append(ikey
.user_key
.ToString());
82 case kTypeSingleDeletion
:
83 state
.append("SingleDelete(");
84 state
.append(ikey
.user_key
.ToString());
87 single_delete_count
++;
89 case kTypeRangeDeletion
:
90 state
.append("DeleteRange(");
91 state
.append(ikey
.user_key
.ToString());
93 state
.append(iter
->value().ToString());
99 state
.append("Merge(");
100 state
.append(ikey
.user_key
.ToString());
102 state
.append(iter
->value().ToString());
112 state
.append(NumberToString(ikey
.sequence
));
115 EXPECT_EQ(b
->HasPut(), put_count
> 0);
116 EXPECT_EQ(b
->HasDelete(), delete_count
> 0);
117 EXPECT_EQ(b
->HasSingleDelete(), single_delete_count
> 0);
118 EXPECT_EQ(b
->HasDeleteRange(), delete_range_count
> 0);
119 EXPECT_EQ(b
->HasMerge(), merge_count
> 0);
121 state
.append(s
.ToString());
122 } else if (count
!= WriteBatchInternal::Count(b
)) {
123 state
.append("CountMismatch()");
129 class WriteBatchTest
: public testing::Test
{};
131 TEST_F(WriteBatchTest
, Empty
) {
133 ASSERT_EQ("", PrintContents(&batch
));
134 ASSERT_EQ(0, WriteBatchInternal::Count(&batch
));
135 ASSERT_EQ(0, batch
.Count());
138 TEST_F(WriteBatchTest
, Multiple
) {
140 batch
.Put(Slice("foo"), Slice("bar"));
141 batch
.Delete(Slice("box"));
142 batch
.DeleteRange(Slice("bar"), Slice("foo"));
143 batch
.Put(Slice("baz"), Slice("boo"));
144 WriteBatchInternal::SetSequence(&batch
, 100);
145 ASSERT_EQ(100U, WriteBatchInternal::Sequence(&batch
));
146 ASSERT_EQ(4, WriteBatchInternal::Count(&batch
));
151 "DeleteRange(bar, foo)@102",
152 PrintContents(&batch
));
153 ASSERT_EQ(4, batch
.Count());
156 TEST_F(WriteBatchTest
, Corruption
) {
158 batch
.Put(Slice("foo"), Slice("bar"));
159 batch
.Delete(Slice("box"));
160 WriteBatchInternal::SetSequence(&batch
, 200);
161 Slice contents
= WriteBatchInternal::Contents(&batch
);
162 WriteBatchInternal::SetContents(&batch
,
163 Slice(contents
.data(),contents
.size()-1));
164 ASSERT_EQ("Put(foo, bar)@200"
165 "Corruption: bad WriteBatch Delete",
166 PrintContents(&batch
));
169 TEST_F(WriteBatchTest
, Append
) {
171 WriteBatchInternal::SetSequence(&b1
, 200);
172 WriteBatchInternal::SetSequence(&b2
, 300);
173 WriteBatchInternal::Append(&b1
, &b2
);
176 ASSERT_EQ(0, b1
.Count());
178 WriteBatchInternal::Append(&b1
, &b2
);
179 ASSERT_EQ("Put(a, va)@200",
181 ASSERT_EQ(1, b1
.Count());
184 WriteBatchInternal::Append(&b1
, &b2
);
185 ASSERT_EQ("Put(a, va)@200"
188 ASSERT_EQ(2, b1
.Count());
190 WriteBatchInternal::Append(&b1
, &b2
);
191 ASSERT_EQ("Put(a, va)@200"
196 ASSERT_EQ(4, b1
.Count());
200 b2
.MarkWalTerminationPoint();
202 WriteBatchInternal::Append(&b1
, &b2
, /*wal only*/ true);
211 ASSERT_EQ(6, b1
.Count());
217 ASSERT_EQ(3, b2
.Count());
220 TEST_F(WriteBatchTest
, SingleDeletion
) {
222 WriteBatchInternal::SetSequence(&batch
, 100);
223 ASSERT_EQ("", PrintContents(&batch
));
224 ASSERT_EQ(0, batch
.Count());
225 batch
.Put("a", "va");
226 ASSERT_EQ("Put(a, va)@100", PrintContents(&batch
));
227 ASSERT_EQ(1, batch
.Count());
228 batch
.SingleDelete("a");
230 "SingleDelete(a)@101"
232 PrintContents(&batch
));
233 ASSERT_EQ(2, batch
.Count());
237 struct TestHandler
: public WriteBatch::Handler
{
239 virtual Status
PutCF(uint32_t column_family_id
, const Slice
& key
,
240 const Slice
& value
) override
{
241 if (column_family_id
== 0) {
242 seen
+= "Put(" + key
.ToString() + ", " + value
.ToString() + ")";
244 seen
+= "PutCF(" + ToString(column_family_id
) + ", " +
245 key
.ToString() + ", " + value
.ToString() + ")";
249 virtual Status
DeleteCF(uint32_t column_family_id
,
250 const Slice
& key
) override
{
251 if (column_family_id
== 0) {
252 seen
+= "Delete(" + key
.ToString() + ")";
254 seen
+= "DeleteCF(" + ToString(column_family_id
) + ", " +
255 key
.ToString() + ")";
259 virtual Status
SingleDeleteCF(uint32_t column_family_id
,
260 const Slice
& key
) override
{
261 if (column_family_id
== 0) {
262 seen
+= "SingleDelete(" + key
.ToString() + ")";
264 seen
+= "SingleDeleteCF(" + ToString(column_family_id
) + ", " +
265 key
.ToString() + ")";
269 virtual Status
DeleteRangeCF(uint32_t column_family_id
,
270 const Slice
& begin_key
,
271 const Slice
& end_key
) override
{
272 if (column_family_id
== 0) {
273 seen
+= "DeleteRange(" + begin_key
.ToString() + ", " +
274 end_key
.ToString() + ")";
276 seen
+= "DeleteRangeCF(" + ToString(column_family_id
) + ", " +
277 begin_key
.ToString() + ", " + end_key
.ToString() + ")";
281 virtual Status
MergeCF(uint32_t column_family_id
, const Slice
& key
,
282 const Slice
& value
) override
{
283 if (column_family_id
== 0) {
284 seen
+= "Merge(" + key
.ToString() + ", " + value
.ToString() + ")";
286 seen
+= "MergeCF(" + ToString(column_family_id
) + ", " +
287 key
.ToString() + ", " + value
.ToString() + ")";
291 virtual void LogData(const Slice
& blob
) override
{
292 seen
+= "LogData(" + blob
.ToString() + ")";
294 virtual Status
MarkBeginPrepare() override
{
295 seen
+= "MarkBeginPrepare()";
298 virtual Status
MarkEndPrepare(const Slice
& xid
) override
{
299 seen
+= "MarkEndPrepare(" + xid
.ToString() + ")";
302 virtual Status
MarkCommit(const Slice
& xid
) override
{
303 seen
+= "MarkCommit(" + xid
.ToString() + ")";
306 virtual Status
MarkRollback(const Slice
& xid
) override
{
307 seen
+= "MarkRollback(" + xid
.ToString() + ")";
313 TEST_F(WriteBatchTest
, PutNotImplemented
) {
315 batch
.Put(Slice("k1"), Slice("v1"));
316 ASSERT_EQ(1, batch
.Count());
317 ASSERT_EQ("Put(k1, v1)@0", PrintContents(&batch
));
319 WriteBatch::Handler handler
;
320 ASSERT_OK(batch
.Iterate(&handler
));
323 TEST_F(WriteBatchTest
, DeleteNotImplemented
) {
325 batch
.Delete(Slice("k2"));
326 ASSERT_EQ(1, batch
.Count());
327 ASSERT_EQ("Delete(k2)@0", PrintContents(&batch
));
329 WriteBatch::Handler handler
;
330 ASSERT_OK(batch
.Iterate(&handler
));
333 TEST_F(WriteBatchTest
, SingleDeleteNotImplemented
) {
335 batch
.SingleDelete(Slice("k2"));
336 ASSERT_EQ(1, batch
.Count());
337 ASSERT_EQ("SingleDelete(k2)@0", PrintContents(&batch
));
339 WriteBatch::Handler handler
;
340 ASSERT_OK(batch
.Iterate(&handler
));
343 TEST_F(WriteBatchTest
, MergeNotImplemented
) {
345 batch
.Merge(Slice("foo"), Slice("bar"));
346 ASSERT_EQ(1, batch
.Count());
347 ASSERT_EQ("Merge(foo, bar)@0", PrintContents(&batch
));
349 WriteBatch::Handler handler
;
350 ASSERT_OK(batch
.Iterate(&handler
));
353 TEST_F(WriteBatchTest
, Blob
) {
355 batch
.Put(Slice("k1"), Slice("v1"));
356 batch
.Put(Slice("k2"), Slice("v2"));
357 batch
.Put(Slice("k3"), Slice("v3"));
358 batch
.PutLogData(Slice("blob1"));
359 batch
.Delete(Slice("k2"));
360 batch
.SingleDelete(Slice("k3"));
361 batch
.PutLogData(Slice("blob2"));
362 batch
.Merge(Slice("foo"), Slice("bar"));
363 ASSERT_EQ(6, batch
.Count());
371 PrintContents(&batch
));
374 batch
.Iterate(&handler
);
387 TEST_F(WriteBatchTest
, PrepareCommit
) {
389 WriteBatchInternal::InsertNoop(&batch
);
390 batch
.Put(Slice("k1"), Slice("v1"));
391 batch
.Put(Slice("k2"), Slice("v2"));
392 batch
.SetSavePoint();
393 WriteBatchInternal::MarkEndPrepare(&batch
, Slice("xid1"));
394 Status s
= batch
.RollbackToSavePoint();
395 ASSERT_EQ(s
, Status::NotFound());
396 WriteBatchInternal::MarkCommit(&batch
, Slice("xid1"));
397 WriteBatchInternal::MarkRollback(&batch
, Slice("xid1"));
398 ASSERT_EQ(2, batch
.Count());
401 batch
.Iterate(&handler
);
406 "MarkEndPrepare(xid1)"
408 "MarkRollback(xid1)",
412 // It requires more than 30GB of memory to run the test. With single memory
413 // allocation of more than 30GB.
414 // Not all platform can run it. Also it runs a long time. So disable it.
415 TEST_F(WriteBatchTest
, DISABLED_ManyUpdates
) {
416 // Insert key and value of 3GB and push total batch size to 12GB.
417 static const size_t kKeyValueSize
= 4u;
418 static const uint32_t kNumUpdates
= 3 << 30;
419 std::string
raw(kKeyValueSize
, 'A');
420 WriteBatch
batch(kNumUpdates
* (4 + kKeyValueSize
* 2) + 1024u);
422 for (uint32_t i
= 0; i
< kNumUpdates
; i
++) {
427 raw
[raw
.length() - 1] = c
;
432 ASSERT_EQ(kNumUpdates
, batch
.Count());
434 struct NoopHandler
: public WriteBatch::Handler
{
435 uint32_t num_seen
= 0;
436 char expected_char
= 'A';
437 virtual Status
PutCF(uint32_t column_family_id
, const Slice
& key
,
438 const Slice
& value
) override
{
439 EXPECT_EQ(kKeyValueSize
, key
.size());
440 EXPECT_EQ(kKeyValueSize
, value
.size());
441 EXPECT_EQ(expected_char
, key
[0]);
442 EXPECT_EQ(expected_char
, value
[0]);
443 EXPECT_EQ(expected_char
, key
[kKeyValueSize
- 1]);
444 EXPECT_EQ(expected_char
, value
[kKeyValueSize
- 1]);
446 if (expected_char
> 'Z') {
452 virtual Status
DeleteCF(uint32_t column_family_id
,
453 const Slice
& key
) override
{
457 virtual Status
SingleDeleteCF(uint32_t column_family_id
,
458 const Slice
& key
) override
{
462 virtual Status
MergeCF(uint32_t column_family_id
, const Slice
& key
,
463 const Slice
& value
) override
{
467 virtual void LogData(const Slice
& blob
) override
{ EXPECT_TRUE(false); }
468 virtual bool Continue() override
{ return num_seen
< kNumUpdates
; }
471 batch
.Iterate(&handler
);
472 ASSERT_EQ(kNumUpdates
, handler
.num_seen
);
475 // The test requires more than 18GB memory to run it, with single memory
476 // allocation of more than 12GB. Not all the platform can run it. So disable it.
477 TEST_F(WriteBatchTest
, DISABLED_LargeKeyValue
) {
478 // Insert key and value of 3GB and push total batch size to 12GB.
479 static const size_t kKeyValueSize
= 3221225472u;
480 std::string
raw(kKeyValueSize
, 'A');
481 WriteBatch
batch(size_t(12884901888ull + 1024u));
482 for (char i
= 0; i
< 2; i
++) {
484 raw
[raw
.length() - 1] = 'A' - i
;
488 ASSERT_EQ(2, batch
.Count());
490 struct NoopHandler
: public WriteBatch::Handler
{
492 virtual Status
PutCF(uint32_t column_family_id
, const Slice
& key
,
493 const Slice
& value
) override
{
494 EXPECT_EQ(kKeyValueSize
, key
.size());
495 EXPECT_EQ(kKeyValueSize
, value
.size());
496 EXPECT_EQ('A' + num_seen
, key
[0]);
497 EXPECT_EQ('A' + num_seen
, value
[0]);
498 EXPECT_EQ('A' - num_seen
, key
[kKeyValueSize
- 1]);
499 EXPECT_EQ('A' - num_seen
, value
[kKeyValueSize
- 1]);
503 virtual Status
DeleteCF(uint32_t column_family_id
,
504 const Slice
& key
) override
{
508 virtual Status
SingleDeleteCF(uint32_t column_family_id
,
509 const Slice
& key
) override
{
513 virtual Status
MergeCF(uint32_t column_family_id
, const Slice
& key
,
514 const Slice
& value
) override
{
518 virtual void LogData(const Slice
& blob
) override
{ EXPECT_TRUE(false); }
519 virtual bool Continue() override
{ return num_seen
< 2; }
522 batch
.Iterate(&handler
);
523 ASSERT_EQ(2, handler
.num_seen
);
526 TEST_F(WriteBatchTest
, Continue
) {
529 struct Handler
: public TestHandler
{
531 virtual Status
PutCF(uint32_t column_family_id
, const Slice
& key
,
532 const Slice
& value
) override
{
534 return TestHandler::PutCF(column_family_id
, key
, value
);
536 virtual Status
DeleteCF(uint32_t column_family_id
,
537 const Slice
& key
) override
{
539 return TestHandler::DeleteCF(column_family_id
, key
);
541 virtual Status
SingleDeleteCF(uint32_t column_family_id
,
542 const Slice
& key
) override
{
544 return TestHandler::SingleDeleteCF(column_family_id
, key
);
546 virtual Status
MergeCF(uint32_t column_family_id
, const Slice
& key
,
547 const Slice
& value
) override
{
549 return TestHandler::MergeCF(column_family_id
, key
, value
);
551 virtual void LogData(const Slice
& blob
) override
{
553 TestHandler::LogData(blob
);
555 virtual bool Continue() override
{ return num_seen
< 5; }
558 batch
.Put(Slice("k1"), Slice("v1"));
559 batch
.Put(Slice("k2"), Slice("v2"));
560 batch
.PutLogData(Slice("blob1"));
561 batch
.Delete(Slice("k1"));
562 batch
.SingleDelete(Slice("k2"));
563 batch
.PutLogData(Slice("blob2"));
564 batch
.Merge(Slice("foo"), Slice("bar"));
565 batch
.Iterate(&handler
);
575 TEST_F(WriteBatchTest
, PutGatherSlices
) {
577 batch
.Put(Slice("foo"), Slice("bar"));
580 // Try a write where the key is one slice but the value is two
581 Slice
key_slice("baz");
582 Slice value_slices
[2] = { Slice("header"), Slice("payload") };
583 batch
.Put(SliceParts(&key_slice
, 1),
584 SliceParts(value_slices
, 2));
588 // One where the key is composite but the value is a single slice
589 Slice key_slices
[3] = { Slice("key"), Slice("part2"), Slice("part3") };
590 Slice
value_slice("value");
591 batch
.Put(SliceParts(key_slices
, 3),
592 SliceParts(&value_slice
, 1));
595 WriteBatchInternal::SetSequence(&batch
, 100);
596 ASSERT_EQ("Put(baz, headerpayload)@101"
598 "Put(keypart2part3, value)@102",
599 PrintContents(&batch
));
600 ASSERT_EQ(3, batch
.Count());
604 class ColumnFamilyHandleImplDummy
: public ColumnFamilyHandleImpl
{
606 explicit ColumnFamilyHandleImplDummy(int id
)
607 : ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id
) {}
608 uint32_t GetID() const override
{ return id_
; }
609 const Comparator
* GetComparator() const override
{
610 return BytewiseComparator();
616 } // namespace anonymous
618 TEST_F(WriteBatchTest
, ColumnFamiliesBatchTest
) {
620 ColumnFamilyHandleImplDummy
zero(0), two(2), three(3), eight(8);
621 batch
.Put(&zero
, Slice("foo"), Slice("bar"));
622 batch
.Put(&two
, Slice("twofoo"), Slice("bar2"));
623 batch
.Put(&eight
, Slice("eightfoo"), Slice("bar8"));
624 batch
.Delete(&eight
, Slice("eightfoo"));
625 batch
.SingleDelete(&two
, Slice("twofoo"));
626 batch
.DeleteRange(&two
, Slice("3foo"), Slice("4foo"));
627 batch
.Merge(&three
, Slice("threethree"), Slice("3three"));
628 batch
.Put(&zero
, Slice("foo"), Slice("bar"));
629 batch
.Merge(Slice("omom"), Slice("nom"));
632 batch
.Iterate(&handler
);
635 "PutCF(2, twofoo, bar2)"
636 "PutCF(8, eightfoo, bar8)"
637 "DeleteCF(8, eightfoo)"
638 "SingleDeleteCF(2, twofoo)"
639 "DeleteRangeCF(2, 3foo, 4foo)"
640 "MergeCF(3, threethree, 3three)"
647 TEST_F(WriteBatchTest
, ColumnFamiliesBatchWithIndexTest
) {
648 WriteBatchWithIndex batch
;
649 ColumnFamilyHandleImplDummy
zero(0), two(2), three(3), eight(8);
650 batch
.Put(&zero
, Slice("foo"), Slice("bar"));
651 batch
.Put(&two
, Slice("twofoo"), Slice("bar2"));
652 batch
.Put(&eight
, Slice("eightfoo"), Slice("bar8"));
653 batch
.Delete(&eight
, Slice("eightfoo"));
654 batch
.SingleDelete(&two
, Slice("twofoo"));
655 batch
.DeleteRange(&two
, Slice("twofoo"), Slice("threefoo"));
656 batch
.Merge(&three
, Slice("threethree"), Slice("3three"));
657 batch
.Put(&zero
, Slice("foo"), Slice("bar"));
658 batch
.Merge(Slice("omom"), Slice("nom"));
660 std::unique_ptr
<WBWIIterator
> iter
;
662 iter
.reset(batch
.NewIterator(&eight
));
663 iter
->Seek("eightfoo");
664 ASSERT_OK(iter
->status());
665 ASSERT_TRUE(iter
->Valid());
666 ASSERT_EQ(WriteType::kPutRecord
, iter
->Entry().type
);
667 ASSERT_EQ("eightfoo", iter
->Entry().key
.ToString());
668 ASSERT_EQ("bar8", iter
->Entry().value
.ToString());
671 ASSERT_OK(iter
->status());
672 ASSERT_TRUE(iter
->Valid());
673 ASSERT_EQ(WriteType::kDeleteRecord
, iter
->Entry().type
);
674 ASSERT_EQ("eightfoo", iter
->Entry().key
.ToString());
677 ASSERT_OK(iter
->status());
678 ASSERT_TRUE(!iter
->Valid());
680 iter
.reset(batch
.NewIterator(&two
));
681 iter
->Seek("twofoo");
682 ASSERT_OK(iter
->status());
683 ASSERT_TRUE(iter
->Valid());
684 ASSERT_EQ(WriteType::kPutRecord
, iter
->Entry().type
);
685 ASSERT_EQ("twofoo", iter
->Entry().key
.ToString());
686 ASSERT_EQ("bar2", iter
->Entry().value
.ToString());
689 ASSERT_OK(iter
->status());
690 ASSERT_TRUE(iter
->Valid());
691 ASSERT_EQ(WriteType::kSingleDeleteRecord
, iter
->Entry().type
);
692 ASSERT_EQ("twofoo", iter
->Entry().key
.ToString());
695 ASSERT_OK(iter
->status());
696 ASSERT_TRUE(iter
->Valid());
697 ASSERT_EQ(WriteType::kDeleteRangeRecord
, iter
->Entry().type
);
698 ASSERT_EQ("twofoo", iter
->Entry().key
.ToString());
699 ASSERT_EQ("threefoo", iter
->Entry().value
.ToString());
702 ASSERT_OK(iter
->status());
703 ASSERT_TRUE(!iter
->Valid());
705 iter
.reset(batch
.NewIterator());
707 ASSERT_OK(iter
->status());
708 ASSERT_TRUE(iter
->Valid());
709 ASSERT_EQ(WriteType::kMergeRecord
, iter
->Entry().type
);
710 ASSERT_EQ("omom", iter
->Entry().key
.ToString());
711 ASSERT_EQ("nom", iter
->Entry().value
.ToString());
714 ASSERT_OK(iter
->status());
715 ASSERT_TRUE(!iter
->Valid());
717 iter
.reset(batch
.NewIterator(&zero
));
719 ASSERT_OK(iter
->status());
720 ASSERT_TRUE(iter
->Valid());
721 ASSERT_EQ(WriteType::kPutRecord
, iter
->Entry().type
);
722 ASSERT_EQ("foo", iter
->Entry().key
.ToString());
723 ASSERT_EQ("bar", iter
->Entry().value
.ToString());
726 ASSERT_OK(iter
->status());
727 ASSERT_TRUE(iter
->Valid());
728 ASSERT_EQ(WriteType::kPutRecord
, iter
->Entry().type
);
729 ASSERT_EQ("foo", iter
->Entry().key
.ToString());
730 ASSERT_EQ("bar", iter
->Entry().value
.ToString());
733 ASSERT_OK(iter
->status());
734 ASSERT_TRUE(iter
->Valid());
735 ASSERT_EQ(WriteType::kMergeRecord
, iter
->Entry().type
);
736 ASSERT_EQ("omom", iter
->Entry().key
.ToString());
737 ASSERT_EQ("nom", iter
->Entry().value
.ToString());
740 ASSERT_OK(iter
->status());
741 ASSERT_TRUE(!iter
->Valid());
744 batch
.GetWriteBatch()->Iterate(&handler
);
747 "PutCF(2, twofoo, bar2)"
748 "PutCF(8, eightfoo, bar8)"
749 "DeleteCF(8, eightfoo)"
750 "SingleDeleteCF(2, twofoo)"
751 "DeleteRangeCF(2, twofoo, threefoo)"
752 "MergeCF(3, threethree, 3three)"
757 #endif // !ROCKSDB_LITE
759 TEST_F(WriteBatchTest
, SavePointTest
) {
762 batch
.SetSavePoint();
766 batch
.SetSavePoint();
770 batch
.SetSavePoint();
771 batch
.SetSavePoint();
773 ASSERT_OK(batch
.RollbackToSavePoint());
779 PrintContents(&batch
));
781 ASSERT_OK(batch
.RollbackToSavePoint());
782 ASSERT_OK(batch
.RollbackToSavePoint());
786 PrintContents(&batch
));
789 batch
.Put("B", "bb");
791 ASSERT_OK(batch
.RollbackToSavePoint());
792 ASSERT_EQ("", PrintContents(&batch
));
794 s
= batch
.RollbackToSavePoint();
795 ASSERT_TRUE(s
.IsNotFound());
796 ASSERT_EQ("", PrintContents(&batch
));
801 batch
.SetSavePoint();
803 batch
.Put("A", "aaa");
805 ASSERT_OK(batch
.RollbackToSavePoint());
809 PrintContents(&batch
));
811 batch
.SetSavePoint();
816 ASSERT_OK(batch
.RollbackToSavePoint());
820 PrintContents(&batch
));
822 s
= batch
.RollbackToSavePoint();
823 ASSERT_TRUE(s
.IsNotFound());
827 PrintContents(&batch
));
831 s
= batch2
.RollbackToSavePoint();
832 ASSERT_TRUE(s
.IsNotFound());
833 ASSERT_EQ("", PrintContents(&batch2
));
836 batch2
.SetSavePoint();
838 s
= batch2
.RollbackToSavePoint();
840 ASSERT_EQ("Delete(A)@0", PrintContents(&batch2
));
843 ASSERT_EQ("", PrintContents(&batch2
));
845 batch2
.SetSavePoint();
848 ASSERT_EQ("Delete(B)@0", PrintContents(&batch2
));
850 batch2
.SetSavePoint();
851 s
= batch2
.RollbackToSavePoint();
853 ASSERT_EQ("Delete(B)@0", PrintContents(&batch2
));
855 s
= batch2
.RollbackToSavePoint();
857 ASSERT_EQ("", PrintContents(&batch2
));
859 s
= batch2
.RollbackToSavePoint();
860 ASSERT_TRUE(s
.IsNotFound());
861 ASSERT_EQ("", PrintContents(&batch2
));
864 TEST_F(WriteBatchTest
, MemoryLimitTest
) {
866 // The header size is 12 bytes. The two Puts take 8 bytes which gives total
867 // of 12 + 8 * 2 = 28 bytes.
868 WriteBatch
batch(0, 28);
870 ASSERT_OK(batch
.Put("a", "...."));
871 ASSERT_OK(batch
.Put("b", "...."));
872 s
= batch
.Put("c", "....");
873 ASSERT_TRUE(s
.IsMemoryLimit());
876 } // namespace rocksdb
878 int main(int argc
, char** argv
) {
879 ::testing::InitGoogleTest(&argc
, argv
);
880 return RUN_ALL_TESTS();