Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc

Issue 2719023007: IndexedDB: Optimize range deletion operations (e.g. clearing a store) (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium 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.
4
5 #include <stddef.h>
6
7 #include <algorithm>
8 #include <cstring>
9 #include <string>
10
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/strings/string_piece.h"
16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
17 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
18 #include "content/browser/indexed_db/leveldb/leveldb_env.h"
19 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
20 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/leveldatabase/env_chromium.h"
23
24 namespace content {
25
26 namespace {
27
28 class SimpleComparator : public LevelDBComparator {
29 public:
30 int Compare(const base::StringPiece& a,
31 const base::StringPiece& b) const override {
32 size_t len = std::min(a.size(), b.size());
33 return memcmp(a.begin(), b.begin(), len);
34 }
35 const char* Name() const override { return "temp_comparator"; }
36 };
37
38 class LevelDBTransactionTest : public testing::Test {
39 public:
40 LevelDBTransactionTest() {}
41 void SetUp() override {
42 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
43 LevelDBDatabase::Open(temp_directory_.GetPath(), &comparator_, &leveldb_);
44 ASSERT_TRUE(leveldb_);
45 }
46 void TearDown() override {}
47
48 protected:
49 // Convenience methods to access the database outside any
50 // transaction to cut down on boilerplate around calls.
51 void Put(const base::StringPiece& key, const std::string& value) {
52 std::string put_value = value;
53 leveldb::Status s = leveldb_->Put(key, &put_value);
54 ASSERT_TRUE(s.ok());
55 }
56
57 void Remove(const base::StringPiece& key) {
58 leveldb::Status s = leveldb_->Remove(key);
59 ASSERT_TRUE(s.ok());
60 }
61
62 void Get(const base::StringPiece& key, std::string* value, bool* found) {
63 leveldb::Status s = leveldb_->Get(key, value, found);
64 ASSERT_TRUE(s.ok());
65 }
66
67 bool Has(const base::StringPiece& key) {
68 bool found;
69 std::string value;
70 leveldb::Status s = leveldb_->Get(key, &value, &found);
71 EXPECT_TRUE(s.ok());
72 return found;
73 }
74
75 // Convenience wrappers for LevelDBTransaction operations to
76 // avoid boilerplate in tests.
77 bool TransactionHas(LevelDBTransaction* transaction,
78 const base::StringPiece& key) {
79 std::string value;
80 bool found;
81 leveldb::Status s = transaction->Get(key, &value, &found);
82 EXPECT_TRUE(s.ok());
83 return found;
84 }
85
86 void TransactionPut(LevelDBTransaction* transaction,
87 const base::StringPiece& key,
88 const std::string& value) {
89 std::string put_value = value;
90 transaction->Put(key, &put_value);
91 }
92
93 int Compare(const base::StringPiece& a, const base::StringPiece& b) const {
94 return comparator_.Compare(a, b);
95 }
96
97 LevelDBDatabase* db() { return leveldb_.get(); }
98
99 private:
100 base::ScopedTempDir temp_directory_;
101 SimpleComparator comparator_;
102 std::unique_ptr<LevelDBDatabase> leveldb_;
103
104 DISALLOW_COPY_AND_ASSIGN(LevelDBTransactionTest);
105 };
106
107 } // namespace
108
109 TEST_F(LevelDBTransactionTest, GetAndPut) {
110 leveldb::Status status;
111
112 const std::string key("key");
113 std::string got_value;
114
115 const std::string old_value("value");
116 Put(key, old_value);
117
118 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db());
119
120 const std::string new_value("new value");
121 Put(key, new_value);
122
123 bool found = false;
124 status = transaction->Get(key, &got_value, &found);
125 EXPECT_TRUE(status.ok());
126 EXPECT_TRUE(found);
127 EXPECT_EQ(Compare(got_value, old_value), 0);
128
129 Get(key, &got_value, &found);
130 EXPECT_TRUE(found);
131 EXPECT_EQ(Compare(got_value, new_value), 0);
132
133 const std::string added_key("added key");
134 const std::string added_value("added value");
135 Put(added_key, added_value);
136
137 Get(added_key, &got_value, &found);
138 EXPECT_TRUE(found);
139 EXPECT_EQ(Compare(got_value, added_value), 0);
140
141 EXPECT_FALSE(TransactionHas(transaction.get(), added_key));
142
143 const std::string another_key("another key");
144 const std::string another_value("another value");
145 TransactionPut(transaction.get(), another_key, another_value);
146
147 status = transaction->Get(another_key, &got_value, &found);
148 EXPECT_TRUE(status.ok());
149 EXPECT_TRUE(found);
150 EXPECT_EQ(Compare(got_value, another_value), 0);
151 }
152
153 TEST_F(LevelDBTransactionTest, Iterator) {
154 const std::string key1("key1");
155 const std::string value1("value1");
156 const std::string key2("key2");
157 const std::string value2("value2");
158
159 Put(key1, value1);
160 Put(key2, value2);
161
162 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db());
163
164 Remove(key2);
165
166 std::unique_ptr<LevelDBIterator> it = transaction->CreateIterator();
167
168 it->Seek(std::string());
169
170 EXPECT_TRUE(it->IsValid());
171 EXPECT_EQ(Compare(it->Key(), key1), 0);
172 EXPECT_EQ(Compare(it->Value(), value1), 0);
173
174 it->Next();
175
176 EXPECT_TRUE(it->IsValid());
177 EXPECT_EQ(Compare(it->Key(), key2), 0);
178 EXPECT_EQ(Compare(it->Value(), value2), 0);
179
180 it->Next();
181
182 EXPECT_FALSE(it->IsValid());
183 }
184
185 TEST_F(LevelDBTransactionTest, Commit) {
186 const std::string key1("key1");
187 const std::string key2("key2");
188 const std::string value1("value1");
189 const std::string value2("value2");
190 const std::string value3("value3");
191
192 std::string got_value;
193 bool found;
194
195 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db());
196
197 TransactionPut(transaction.get(), key1, value1);
198 TransactionPut(transaction.get(), key2, value2);
199 TransactionPut(transaction.get(), key2, value3);
200
201 leveldb::Status status = transaction->Commit();
202 EXPECT_TRUE(status.ok());
203
204 Get(key1, &got_value, &found);
205 EXPECT_TRUE(found);
206 EXPECT_EQ(value1, got_value);
207
208 Get(key2, &got_value, &found);
209 EXPECT_TRUE(found);
210 EXPECT_EQ(value3, got_value);
211 }
212
213 namespace {
214 enum RangePrepareMode {
215 DataInMemory,
216 DataInDatabase,
217 DataMixed,
218 };
219 } // namespace
220
221 class LevelDBTransactionRangeTest
222 : public LevelDBTransactionTest,
223 public testing::WithParamInterface<RangePrepareMode> {
224 public:
225 LevelDBTransactionRangeTest() {}
226 void SetUp() override {
227 LevelDBTransactionTest::SetUp();
228
229 switch (GetParam()) {
230 case DataInMemory:
231 transaction_ = new LevelDBTransaction(db());
232
233 TransactionPut(transaction_.get(), key_before_range_, value_);
234 TransactionPut(transaction_.get(), range_start_, value_);
235 TransactionPut(transaction_.get(), key_in_range1_, value_);
236 TransactionPut(transaction_.get(), key_in_range2_, value_);
237 TransactionPut(transaction_.get(), range_end_, value_);
238 TransactionPut(transaction_.get(), key_after_range_, value_);
239 break;
240
241 case DataInDatabase:
242 Put(key_before_range_, value_);
243 Put(range_start_, value_);
244 Put(key_in_range1_, value_);
245 Put(key_in_range2_, value_);
246 Put(range_end_, value_);
247 Put(key_after_range_, value_);
248
249 transaction_ = new LevelDBTransaction(db());
250 break;
251
252 case DataMixed:
253 Put(key_before_range_, value_);
254 Put(key_in_range1_, value_);
255 Put(range_end_, value_);
256
257 transaction_ = new LevelDBTransaction(db());
258
259 TransactionPut(transaction_.get(), range_start_, value_);
260 TransactionPut(transaction_.get(), key_in_range2_, value_);
261 TransactionPut(transaction_.get(), key_after_range_, value_);
262 break;
263 }
264 }
265
266 protected:
267 const std::string key_before_range_ = "a";
268 const std::string range_start_ = "b";
269 const std::string key_in_range1_ = "c";
270 const std::string key_in_range2_ = "d";
271 const std::string range_end_ = "e";
272 const std::string key_after_range_ = "f";
273 const std::string value_ = "value";
274
275 scoped_refptr<LevelDBTransaction> transaction_;
276
277 private:
278 DISALLOW_COPY_AND_ASSIGN(LevelDBTransactionRangeTest);
279 };
280
281 TEST_P(LevelDBTransactionRangeTest, RemoveRangeUpperClosed) {
282 leveldb::Status status;
283
284 const bool upper_open = false;
285 status = transaction_->RemoveRange(range_start_, range_end_, upper_open);
286 EXPECT_TRUE(status.ok());
287
288 EXPECT_TRUE(TransactionHas(transaction_.get(), key_before_range_));
289 EXPECT_FALSE(TransactionHas(transaction_.get(), range_start_));
290 EXPECT_FALSE(TransactionHas(transaction_.get(), key_in_range1_));
291 EXPECT_FALSE(TransactionHas(transaction_.get(), key_in_range2_));
292 EXPECT_FALSE(TransactionHas(transaction_.get(), range_end_));
293 EXPECT_TRUE(TransactionHas(transaction_.get(), key_after_range_));
294
295 status = transaction_->Commit();
296 EXPECT_TRUE(status.ok());
297
298 EXPECT_TRUE(Has(key_before_range_));
299 EXPECT_FALSE(Has(range_start_));
300 EXPECT_FALSE(Has(key_in_range1_));
301 EXPECT_FALSE(Has(key_in_range2_));
302 EXPECT_FALSE(Has(range_end_));
303 EXPECT_TRUE(Has(key_after_range_));
304 }
305
306 TEST_P(LevelDBTransactionRangeTest, RemoveRangeUpperOpen) {
307 leveldb::Status status;
308
309 const bool upper_open = true;
310 status = transaction_->RemoveRange(range_start_, range_end_, upper_open);
311 EXPECT_TRUE(status.ok());
312
313 EXPECT_TRUE(TransactionHas(transaction_.get(), key_before_range_));
314 EXPECT_FALSE(TransactionHas(transaction_.get(), range_start_));
315 EXPECT_FALSE(TransactionHas(transaction_.get(), key_in_range1_));
316 EXPECT_FALSE(TransactionHas(transaction_.get(), key_in_range2_));
317 EXPECT_TRUE(TransactionHas(transaction_.get(), range_end_));
318 EXPECT_TRUE(TransactionHas(transaction_.get(), key_after_range_));
319
320 status = transaction_->Commit();
321 EXPECT_TRUE(status.ok());
322
323 EXPECT_TRUE(Has(key_before_range_));
324 EXPECT_FALSE(Has(range_start_));
325 EXPECT_FALSE(Has(key_in_range1_));
326 EXPECT_FALSE(Has(key_in_range2_));
327 EXPECT_TRUE(Has(range_end_));
328 EXPECT_TRUE(Has(key_after_range_));
329 }
330
331 TEST_P(LevelDBTransactionRangeTest, RemoveRangeIteratorRetainsKey) {
332 leveldb::Status status;
333
334 std::unique_ptr<LevelDBIterator> it = transaction_->CreateIterator();
335 status = it->Seek(key_in_range1_);
336 EXPECT_TRUE(status.ok());
337 EXPECT_TRUE(it->IsValid());
338 EXPECT_EQ(Compare(key_in_range1_, it->Key()), 0);
339 status = it->Next();
340 EXPECT_TRUE(status.ok());
341 EXPECT_TRUE(it->IsValid());
342 EXPECT_EQ(Compare(key_in_range2_, it->Key()), 0);
343
344 const bool upper_open = false;
345 status = transaction_->RemoveRange(range_start_, range_end_, upper_open);
346 EXPECT_TRUE(status.ok());
347
348 EXPECT_TRUE(it->IsValid());
349 EXPECT_EQ(Compare(key_in_range2_, it->Key()), 0);
350
351 status = it->Next();
352 EXPECT_TRUE(status.ok());
353 EXPECT_TRUE(it->IsValid());
354 EXPECT_EQ(Compare(key_after_range_, it->Key()), 0);
355 }
356
357 INSTANTIATE_TEST_CASE_P(LevelDBTransactionRangeTests,
358 LevelDBTransactionRangeTest,
359 ::testing::Values(DataInMemory,
360 DataInDatabase,
361 DataMixed));
362
363 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698