1 // Copyright (c) 2013 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.
5 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/time/time.h"
10 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
11 #include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
12 #include "third_party/leveldatabase/src/include/leveldb/db.h"
14 using base::StringPiece
;
18 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase
* db
)
21 comparator_(db
->Comparator()),
22 data_comparator_(comparator_
),
23 data_(data_comparator_
),
26 LevelDBTransaction::Record::Record() : deleted(false) {}
27 LevelDBTransaction::Record::~Record() {}
29 void LevelDBTransaction::Clear() {
30 for (const auto& it
: data_
)
35 LevelDBTransaction::~LevelDBTransaction() { Clear(); }
37 void LevelDBTransaction::Set(const StringPiece
& key
,
41 DataType::iterator it
= data_
.find(key
);
43 if (it
== data_
.end()) {
44 Record
* record
= new Record();
45 record
->key
.assign(key
.begin(), key
.end() - key
.begin());
46 record
->value
.swap(*value
);
47 record
->deleted
= deleted
;
48 data_
[record
->key
] = record
;
53 it
->second
->value
.swap(*value
);
54 it
->second
->deleted
= deleted
;
57 void LevelDBTransaction::Put(const StringPiece
& key
, std::string
* value
) {
58 Set(key
, value
, false);
61 void LevelDBTransaction::Remove(const StringPiece
& key
) {
63 Set(key
, &empty
, true);
66 leveldb::Status
LevelDBTransaction::Get(const StringPiece
& key
,
71 std::string
string_key(key
.begin(), key
.end() - key
.begin());
72 DataType::const_iterator it
= data_
.find(string_key
);
74 if (it
!= data_
.end()) {
75 if (it
->second
->deleted
)
76 return leveldb::Status::OK();
78 *value
= it
->second
->value
;
80 return leveldb::Status::OK();
83 leveldb::Status s
= db_
->Get(key
, value
, found
, &snapshot_
);
89 leveldb::Status
LevelDBTransaction::Commit() {
94 return leveldb::Status::OK();
97 base::TimeTicks begin_time
= base::TimeTicks::Now();
98 scoped_ptr
<LevelDBWriteBatch
> write_batch
= LevelDBWriteBatch::Create();
100 for (const auto& iterator
: data_
) {
101 if (!iterator
.second
->deleted
)
102 write_batch
->Put(iterator
.first
, iterator
.second
->value
);
104 write_batch
->Remove(iterator
.first
);
107 leveldb::Status s
= db_
->Write(*write_batch
);
111 UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.Transaction.CommitTime",
112 base::TimeTicks::Now() - begin_time
);
117 void LevelDBTransaction::Rollback() {
123 scoped_ptr
<LevelDBIterator
> LevelDBTransaction::CreateIterator() {
124 return TransactionIterator::Create(this);
127 scoped_ptr
<LevelDBTransaction::DataIterator
>
128 LevelDBTransaction::DataIterator::Create(LevelDBTransaction
* transaction
) {
129 return make_scoped_ptr(new DataIterator(transaction
));
132 bool LevelDBTransaction::DataIterator::IsValid() const {
133 return iterator_
!= data_
->end();
136 leveldb::Status
LevelDBTransaction::DataIterator::SeekToLast() {
137 iterator_
= data_
->end();
138 if (iterator_
!= data_
->begin())
140 return leveldb::Status::OK();
143 leveldb::Status
LevelDBTransaction::DataIterator::Seek(
144 const StringPiece
& target
) {
145 iterator_
= data_
->lower_bound(target
);
146 return leveldb::Status::OK();
149 leveldb::Status
LevelDBTransaction::DataIterator::Next() {
152 return leveldb::Status::OK();
155 leveldb::Status
LevelDBTransaction::DataIterator::Prev() {
157 if (iterator_
!= data_
->begin())
160 iterator_
= data_
->end();
161 return leveldb::Status::OK();
164 StringPiece
LevelDBTransaction::DataIterator::Key() const {
166 return iterator_
->first
;
169 StringPiece
LevelDBTransaction::DataIterator::Value() const {
171 DCHECK(!IsDeleted());
172 return iterator_
->second
->value
;
175 bool LevelDBTransaction::DataIterator::IsDeleted() const {
177 return iterator_
->second
->deleted
;
180 LevelDBTransaction::DataIterator::~DataIterator() {}
182 LevelDBTransaction::DataIterator::DataIterator(LevelDBTransaction
* transaction
)
183 : data_(&transaction
->data_
),
184 iterator_(data_
->end()) {}
186 scoped_ptr
<LevelDBTransaction::TransactionIterator
>
187 LevelDBTransaction::TransactionIterator::Create(
188 scoped_refptr
<LevelDBTransaction
> transaction
) {
189 return make_scoped_ptr(new TransactionIterator(transaction
));
192 LevelDBTransaction::TransactionIterator::TransactionIterator(
193 scoped_refptr
<LevelDBTransaction
> transaction
)
194 : transaction_(transaction
),
195 comparator_(transaction_
->comparator_
),
196 data_iterator_(DataIterator::Create(transaction_
.get())),
197 db_iterator_(transaction_
->db_
->CreateIterator(&transaction_
->snapshot_
)),
200 data_changed_(false) {
201 transaction_
->RegisterIterator(this);
204 LevelDBTransaction::TransactionIterator::~TransactionIterator() {
205 transaction_
->UnregisterIterator(this);
208 bool LevelDBTransaction::TransactionIterator::IsValid() const {
212 leveldb::Status
LevelDBTransaction::TransactionIterator::SeekToLast() {
213 leveldb::Status s
= data_iterator_
->SeekToLast();
215 s
= db_iterator_
->SeekToLast();
218 direction_
= REVERSE
;
220 HandleConflictsAndDeletes();
221 SetCurrentIteratorToLargestKey();
225 leveldb::Status
LevelDBTransaction::TransactionIterator::Seek(
226 const StringPiece
& target
) {
227 leveldb::Status s
= data_iterator_
->Seek(target
);
229 s
= db_iterator_
->Seek(target
);
232 direction_
= FORWARD
;
234 HandleConflictsAndDeletes();
235 SetCurrentIteratorToSmallestKey();
239 leveldb::Status
LevelDBTransaction::TransactionIterator::Next() {
242 RefreshDataIterator();
245 if (direction_
!= FORWARD
) {
246 // Ensure the non-current iterator is positioned after Key().
248 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
249 ? data_iterator_
.get()
250 : db_iterator_
.get();
252 non_current
->Seek(Key());
253 if (non_current
->IsValid() &&
254 !comparator_
->Compare(non_current
->Key(), Key())) {
255 // Take an extra step so the non-current key is
256 // strictly greater than Key().
257 s
= non_current
->Next();
261 DCHECK(!non_current
->IsValid() ||
262 comparator_
->Compare(non_current
->Key(), Key()) > 0);
264 direction_
= FORWARD
;
267 s
= current_
->Next();
270 HandleConflictsAndDeletes();
271 SetCurrentIteratorToSmallestKey();
272 return leveldb::Status::OK();
275 leveldb::Status
LevelDBTransaction::TransactionIterator::Prev() {
279 RefreshDataIterator();
281 if (direction_
!= REVERSE
) {
282 // Ensure the non-current iterator is positioned before Key().
284 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
285 ? data_iterator_
.get()
286 : db_iterator_
.get();
288 s
= non_current
->Seek(Key());
291 if (non_current
->IsValid()) {
292 // Iterator is at first entry >= Key().
293 // Step back once to entry < key.
294 // This is why we don't check for the keys being the same before
295 // stepping, like we do in Next() above.
298 // Iterator has no entries >= Key(). Position at last entry.
299 non_current
->SeekToLast();
301 DCHECK(!non_current
->IsValid() ||
302 comparator_
->Compare(non_current
->Key(), Key()) < 0);
304 direction_
= REVERSE
;
307 s
= current_
->Prev();
310 HandleConflictsAndDeletes();
311 SetCurrentIteratorToLargestKey();
312 return leveldb::Status::OK();
315 StringPiece
LevelDBTransaction::TransactionIterator::Key() const {
318 RefreshDataIterator();
319 return current_
->Key();
322 StringPiece
LevelDBTransaction::TransactionIterator::Value() const {
325 RefreshDataIterator();
326 return current_
->Value();
329 void LevelDBTransaction::TransactionIterator::DataChanged() {
330 data_changed_
= true;
333 void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const {
334 DCHECK(data_changed_
);
336 data_changed_
= false;
338 if (data_iterator_
->IsValid() && data_iterator_
.get() == current_
) {
342 if (db_iterator_
->IsValid()) {
343 // There could be new records in data that we should iterate over.
345 if (direction_
== FORWARD
) {
346 // Try to seek data iterator to something greater than the db iterator.
347 data_iterator_
->Seek(db_iterator_
->Key());
348 if (data_iterator_
->IsValid() &&
349 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
350 // If equal, take another step so the data iterator is strictly greater.
351 data_iterator_
->Next();
354 // If going backward, seek to a key less than the db iterator.
355 DCHECK_EQ(REVERSE
, direction_
);
356 data_iterator_
->Seek(db_iterator_
->Key());
357 if (data_iterator_
->IsValid())
358 data_iterator_
->Prev();
363 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const {
364 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) < 0;
367 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const {
368 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) > 0;
371 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
377 if (data_iterator_
->IsValid() && db_iterator_
->IsValid() &&
378 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
379 // For equal keys, the data iterator takes precedence, so move the
380 // database iterator another step.
381 if (direction_
== FORWARD
)
382 db_iterator_
->Next();
384 db_iterator_
->Prev();
387 // Skip over delete markers in the data iterator until it catches up with
389 if (data_iterator_
->IsValid() && data_iterator_
->IsDeleted()) {
390 if (direction_
== FORWARD
&&
391 (!db_iterator_
->IsValid() || DataIteratorIsLower())) {
392 data_iterator_
->Next();
394 } else if (direction_
== REVERSE
&&
395 (!db_iterator_
->IsValid() || DataIteratorIsHigher())) {
396 data_iterator_
->Prev();
404 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
405 LevelDBIterator
* smallest
= 0;
407 if (data_iterator_
->IsValid())
408 smallest
= data_iterator_
.get();
410 if (db_iterator_
->IsValid()) {
412 comparator_
->Compare(db_iterator_
->Key(), smallest
->Key()) < 0)
413 smallest
= db_iterator_
.get();
419 void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() {
420 LevelDBIterator
* largest
= 0;
422 if (data_iterator_
->IsValid())
423 largest
= data_iterator_
.get();
425 if (db_iterator_
->IsValid()) {
427 comparator_
->Compare(db_iterator_
->Key(), largest
->Key()) > 0)
428 largest
= db_iterator_
.get();
434 void LevelDBTransaction::RegisterIterator(TransactionIterator
* iterator
) {
435 DCHECK(iterators_
.find(iterator
) == iterators_
.end());
436 iterators_
.insert(iterator
);
439 void LevelDBTransaction::UnregisterIterator(TransactionIterator
* iterator
) {
440 DCHECK(iterators_
.find(iterator
) != iterators_
.end());
441 iterators_
.erase(iterator
);
444 void LevelDBTransaction::NotifyIterators() {
445 for (auto* transaction_iterator
: iterators_
)
446 transaction_iterator
->DataChanged();
449 scoped_ptr
<LevelDBDirectTransaction
> LevelDBDirectTransaction::Create(
450 LevelDBDatabase
* db
) {
451 return make_scoped_ptr(new LevelDBDirectTransaction(db
));
454 LevelDBDirectTransaction::LevelDBDirectTransaction(LevelDBDatabase
* db
)
455 : db_(db
), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {}
457 LevelDBDirectTransaction::~LevelDBDirectTransaction() {
458 write_batch_
->Clear();
461 void LevelDBDirectTransaction::Put(const StringPiece
& key
,
462 const std::string
* value
) {
464 write_batch_
->Put(key
, *value
);
467 leveldb::Status
LevelDBDirectTransaction::Get(const StringPiece
& key
,
473 leveldb::Status s
= db_
->Get(key
, value
, found
);
474 DCHECK(s
.ok() || !*found
);
478 void LevelDBDirectTransaction::Remove(const StringPiece
& key
) {
480 write_batch_
->Remove(key
);
483 leveldb::Status
LevelDBDirectTransaction::Commit() {
486 leveldb::Status s
= db_
->Write(*write_batch_
);
489 write_batch_
->Clear();
494 } // namespace content