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 | |
12 | namespace leveldb { |
13 | |
14 | static 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 | |
54 | TEST(WriteBatchTest, Empty) { |
55 | WriteBatch batch; |
56 | ASSERT_EQ("" , PrintContents(&batch)); |
57 | ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); |
58 | } |
59 | |
60 | TEST(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 | |
75 | TEST(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 | |
89 | TEST(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 | |
115 | TEST(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 | |