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
5#include "gtest/gtest.h"
6#include "db/memtable.h"
7#include "db/write_batch_internal.h"
8#include "leveldb/db.h"
9#include "leveldb/env.h"
10#include "util/logging.h"
11
12namespace leveldb {
13
14static std::string PrintContents(WriteBatch* b) {
15 InternalKeyComparator cmp(BytewiseComparator());
16 MemTable* mem = new MemTable(cmp);
17 mem->Ref();
18 std::string state;
19 Status s = WriteBatchInternal::InsertInto(b, mem);
20 int count = 0;
21 Iterator* iter = mem->NewIterator();
22 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
23 ParsedInternalKey ikey;
24 EXPECT_TRUE(ParseInternalKey(iter->key(), &ikey));
25 switch (ikey.type) {
26 case kTypeValue:
27 state.append("Put(");
28 state.append(ikey.user_key.ToString());
29 state.append(", ");
30 state.append(iter->value().ToString());
31 state.append(")");
32 count++;
33 break;
34 case kTypeDeletion:
35 state.append("Delete(");
36 state.append(ikey.user_key.ToString());
37 state.append(")");
38 count++;
39 break;
40 }
41 state.append("@");
42 state.append(NumberToString(ikey.sequence));
43 }
44 delete iter;
45 if (!s.ok()) {
46 state.append("ParseError()");
47 } else if (count != WriteBatchInternal::Count(b)) {
48 state.append("CountMismatch()");
49 }
50 mem->Unref();
51 return state;
52}
53
54TEST(WriteBatchTest, Empty) {
55 WriteBatch batch;
56 ASSERT_EQ("", PrintContents(&batch));
57 ASSERT_EQ(0, WriteBatchInternal::Count(&batch));
58}
59
60TEST(WriteBatchTest, Multiple) {
61 WriteBatch batch;
62 batch.Put(Slice("foo"), Slice("bar"));
63 batch.Delete(Slice("box"));
64 batch.Put(Slice("baz"), Slice("boo"));
65 WriteBatchInternal::SetSequence(&batch, 100);
66 ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch));
67 ASSERT_EQ(3, WriteBatchInternal::Count(&batch));
68 ASSERT_EQ(
69 "Put(baz, boo)@102"
70 "Delete(box)@101"
71 "Put(foo, bar)@100",
72 PrintContents(&batch));
73}
74
75TEST(WriteBatchTest, Corruption) {
76 WriteBatch batch;
77 batch.Put(Slice("foo"), Slice("bar"));
78 batch.Delete(Slice("box"));
79 WriteBatchInternal::SetSequence(&batch, 200);
80 Slice contents = WriteBatchInternal::Contents(&batch);
81 WriteBatchInternal::SetContents(&batch,
82 Slice(contents.data(), contents.size() - 1));
83 ASSERT_EQ(
84 "Put(foo, bar)@200"
85 "ParseError()",
86 PrintContents(&batch));
87}
88
89TEST(WriteBatchTest, Append) {
90 WriteBatch b1, b2;
91 WriteBatchInternal::SetSequence(&b1, 200);
92 WriteBatchInternal::SetSequence(&b2, 300);
93 b1.Append(b2);
94 ASSERT_EQ("", PrintContents(&b1));
95 b2.Put("a", "va");
96 b1.Append(b2);
97 ASSERT_EQ("Put(a, va)@200", PrintContents(&b1));
98 b2.Clear();
99 b2.Put("b", "vb");
100 b1.Append(b2);
101 ASSERT_EQ(
102 "Put(a, va)@200"
103 "Put(b, vb)@201",
104 PrintContents(&b1));
105 b2.Delete("foo");
106 b1.Append(b2);
107 ASSERT_EQ(
108 "Put(a, va)@200"
109 "Put(b, vb)@202"
110 "Put(b, vb)@201"
111 "Delete(foo)@203",
112 PrintContents(&b1));
113}
114
115TEST(WriteBatchTest, ApproximateSize) {
116 WriteBatch batch;
117 size_t empty_size = batch.ApproximateSize();
118
119 batch.Put(Slice("foo"), Slice("bar"));
120 size_t one_key_size = batch.ApproximateSize();
121 ASSERT_LT(empty_size, one_key_size);
122
123 batch.Put(Slice("baz"), Slice("boo"));
124 size_t two_keys_size = batch.ApproximateSize();
125 ASSERT_LT(one_key_size, two_keys_size);
126
127 batch.Delete(Slice("box"));
128 size_t post_delete_size = batch.ApproximateSize();
129 ASSERT_LT(two_keys_size, post_delete_size);
130}
131
132} // namespace leveldb
133