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 (DataType::iterator it
= data_
.begin(); it
!= data_
.end(); ++it
) {
36 LevelDBTransaction::~LevelDBTransaction() { Clear(); }
38 void LevelDBTransaction::Set(const StringPiece
& key
,
42 DataType::iterator it
= data_
.find(key
);
44 if (it
== data_
.end()) {
45 Record
* record
= new Record();
46 record
->key
.assign(key
.begin(), key
.end() - key
.begin());
47 record
->value
.swap(*value
);
48 record
->deleted
= deleted
;
49 data_
[record
->key
] = record
;
54 it
->second
->value
.swap(*value
);
55 it
->second
->deleted
= deleted
;
58 void LevelDBTransaction::Put(const StringPiece
& key
, std::string
* value
) {
59 Set(key
, value
, false);
62 void LevelDBTransaction::Remove(const StringPiece
& key
) {
64 Set(key
, &empty
, true);
67 leveldb::Status
LevelDBTransaction::Get(const StringPiece
& key
,
72 std::string
string_key(key
.begin(), key
.end() - key
.begin());
73 DataType::const_iterator it
= data_
.find(string_key
);
75 if (it
!= data_
.end()) {
76 if (it
->second
->deleted
)
77 return leveldb::Status::OK();
79 *value
= it
->second
->value
;
81 return leveldb::Status::OK();
84 leveldb::Status s
= db_
->Get(key
, value
, found
, &snapshot_
);
90 leveldb::Status
LevelDBTransaction::Commit() {
95 return leveldb::Status::OK();
98 base::TimeTicks begin_time
= base::TimeTicks::Now();
99 scoped_ptr
<LevelDBWriteBatch
> write_batch
= LevelDBWriteBatch::Create();
101 for (DataType::iterator iterator
= data_
.begin(); iterator
!= data_
.end();
103 if (!iterator
->second
->deleted
)
104 write_batch
->Put(iterator
->first
, iterator
->second
->value
);
106 write_batch
->Remove(iterator
->first
);
109 leveldb::Status s
= db_
->Write(*write_batch
);
113 UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.Transaction.CommitTime",
114 base::TimeTicks::Now() - begin_time
);
119 void LevelDBTransaction::Rollback() {
125 scoped_ptr
<LevelDBIterator
> LevelDBTransaction::CreateIterator() {
126 return TransactionIterator::Create(this).PassAs
<LevelDBIterator
>();
129 scoped_ptr
<LevelDBTransaction::DataIterator
>
130 LevelDBTransaction::DataIterator::Create(LevelDBTransaction
* transaction
) {
131 return make_scoped_ptr(new DataIterator(transaction
));
134 bool LevelDBTransaction::DataIterator::IsValid() const {
135 return iterator_
!= data_
->end();
138 leveldb::Status
LevelDBTransaction::DataIterator::SeekToLast() {
139 iterator_
= data_
->end();
140 if (iterator_
!= data_
->begin())
142 return leveldb::Status::OK();
145 leveldb::Status
LevelDBTransaction::DataIterator::Seek(
146 const StringPiece
& target
) {
147 iterator_
= data_
->lower_bound(target
);
148 return leveldb::Status::OK();
151 leveldb::Status
LevelDBTransaction::DataIterator::Next() {
154 return leveldb::Status::OK();
157 leveldb::Status
LevelDBTransaction::DataIterator::Prev() {
159 if (iterator_
!= data_
->begin())
162 iterator_
= data_
->end();
163 return leveldb::Status::OK();
166 StringPiece
LevelDBTransaction::DataIterator::Key() const {
168 return iterator_
->first
;
171 StringPiece
LevelDBTransaction::DataIterator::Value() const {
173 DCHECK(!IsDeleted());
174 return iterator_
->second
->value
;
177 bool LevelDBTransaction::DataIterator::IsDeleted() const {
179 return iterator_
->second
->deleted
;
182 LevelDBTransaction::DataIterator::~DataIterator() {}
184 LevelDBTransaction::DataIterator::DataIterator(LevelDBTransaction
* transaction
)
185 : data_(&transaction
->data_
),
186 iterator_(data_
->end()) {}
188 scoped_ptr
<LevelDBTransaction::TransactionIterator
>
189 LevelDBTransaction::TransactionIterator::Create(
190 scoped_refptr
<LevelDBTransaction
> transaction
) {
191 return make_scoped_ptr(new TransactionIterator(transaction
));
194 LevelDBTransaction::TransactionIterator::TransactionIterator(
195 scoped_refptr
<LevelDBTransaction
> transaction
)
196 : transaction_(transaction
),
197 comparator_(transaction_
->comparator_
),
198 data_iterator_(DataIterator::Create(transaction_
.get())),
199 db_iterator_(transaction_
->db_
->CreateIterator(&transaction_
->snapshot_
)),
202 data_changed_(false) {
203 transaction_
->RegisterIterator(this);
206 LevelDBTransaction::TransactionIterator::~TransactionIterator() {
207 transaction_
->UnregisterIterator(this);
210 bool LevelDBTransaction::TransactionIterator::IsValid() const {
214 leveldb::Status
LevelDBTransaction::TransactionIterator::SeekToLast() {
215 leveldb::Status s
= data_iterator_
->SeekToLast();
217 s
= db_iterator_
->SeekToLast();
220 direction_
= REVERSE
;
222 HandleConflictsAndDeletes();
223 SetCurrentIteratorToLargestKey();
227 leveldb::Status
LevelDBTransaction::TransactionIterator::Seek(
228 const StringPiece
& target
) {
229 leveldb::Status s
= data_iterator_
->Seek(target
);
231 s
= db_iterator_
->Seek(target
);
234 direction_
= FORWARD
;
236 HandleConflictsAndDeletes();
237 SetCurrentIteratorToSmallestKey();
241 leveldb::Status
LevelDBTransaction::TransactionIterator::Next() {
244 RefreshDataIterator();
247 if (direction_
!= FORWARD
) {
248 // Ensure the non-current iterator is positioned after Key().
250 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
251 ? data_iterator_
.get()
252 : db_iterator_
.get();
254 non_current
->Seek(Key());
255 if (non_current
->IsValid() &&
256 !comparator_
->Compare(non_current
->Key(), Key())) {
257 // Take an extra step so the non-current key is
258 // strictly greater than Key().
259 s
= non_current
->Next();
263 DCHECK(!non_current
->IsValid() ||
264 comparator_
->Compare(non_current
->Key(), Key()) > 0);
266 direction_
= FORWARD
;
269 s
= current_
->Next();
272 HandleConflictsAndDeletes();
273 SetCurrentIteratorToSmallestKey();
274 return leveldb::Status::OK();
277 leveldb::Status
LevelDBTransaction::TransactionIterator::Prev() {
281 RefreshDataIterator();
283 if (direction_
!= REVERSE
) {
284 // Ensure the non-current iterator is positioned before Key().
286 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
287 ? data_iterator_
.get()
288 : db_iterator_
.get();
290 s
= non_current
->Seek(Key());
293 if (non_current
->IsValid()) {
294 // Iterator is at first entry >= Key().
295 // Step back once to entry < key.
296 // This is why we don't check for the keys being the same before
297 // stepping, like we do in Next() above.
300 // Iterator has no entries >= Key(). Position at last entry.
301 non_current
->SeekToLast();
303 DCHECK(!non_current
->IsValid() ||
304 comparator_
->Compare(non_current
->Key(), Key()) < 0);
306 direction_
= REVERSE
;
309 s
= current_
->Prev();
312 HandleConflictsAndDeletes();
313 SetCurrentIteratorToLargestKey();
314 return leveldb::Status::OK();
317 StringPiece
LevelDBTransaction::TransactionIterator::Key() const {
320 RefreshDataIterator();
321 return current_
->Key();
324 StringPiece
LevelDBTransaction::TransactionIterator::Value() const {
327 RefreshDataIterator();
328 return current_
->Value();
331 void LevelDBTransaction::TransactionIterator::DataChanged() {
332 data_changed_
= true;
335 void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const {
336 DCHECK(data_changed_
);
338 data_changed_
= false;
340 if (data_iterator_
->IsValid() && data_iterator_
.get() == current_
) {
344 if (db_iterator_
->IsValid()) {
345 // There could be new records in data that we should iterate over.
347 if (direction_
== FORWARD
) {
348 // Try to seek data iterator to something greater than the db iterator.
349 data_iterator_
->Seek(db_iterator_
->Key());
350 if (data_iterator_
->IsValid() &&
351 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
352 // If equal, take another step so the data iterator is strictly greater.
353 data_iterator_
->Next();
356 // If going backward, seek to a key less than the db iterator.
357 DCHECK_EQ(REVERSE
, direction_
);
358 data_iterator_
->Seek(db_iterator_
->Key());
359 if (data_iterator_
->IsValid())
360 data_iterator_
->Prev();
365 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const {
366 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) < 0;
369 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const {
370 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) > 0;
373 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
379 if (data_iterator_
->IsValid() && db_iterator_
->IsValid() &&
380 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
381 // For equal keys, the data iterator takes precedence, so move the
382 // database iterator another step.
383 if (direction_
== FORWARD
)
384 db_iterator_
->Next();
386 db_iterator_
->Prev();
389 // Skip over delete markers in the data iterator until it catches up with
391 if (data_iterator_
->IsValid() && data_iterator_
->IsDeleted()) {
392 if (direction_
== FORWARD
&&
393 (!db_iterator_
->IsValid() || DataIteratorIsLower())) {
394 data_iterator_
->Next();
396 } else if (direction_
== REVERSE
&&
397 (!db_iterator_
->IsValid() || DataIteratorIsHigher())) {
398 data_iterator_
->Prev();
406 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
407 LevelDBIterator
* smallest
= 0;
409 if (data_iterator_
->IsValid())
410 smallest
= data_iterator_
.get();
412 if (db_iterator_
->IsValid()) {
414 comparator_
->Compare(db_iterator_
->Key(), smallest
->Key()) < 0)
415 smallest
= db_iterator_
.get();
421 void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() {
422 LevelDBIterator
* largest
= 0;
424 if (data_iterator_
->IsValid())
425 largest
= data_iterator_
.get();
427 if (db_iterator_
->IsValid()) {
429 comparator_
->Compare(db_iterator_
->Key(), largest
->Key()) > 0)
430 largest
= db_iterator_
.get();
436 void LevelDBTransaction::RegisterIterator(TransactionIterator
* iterator
) {
437 DCHECK(iterators_
.find(iterator
) == iterators_
.end());
438 iterators_
.insert(iterator
);
441 void LevelDBTransaction::UnregisterIterator(TransactionIterator
* iterator
) {
442 DCHECK(iterators_
.find(iterator
) != iterators_
.end());
443 iterators_
.erase(iterator
);
446 void LevelDBTransaction::NotifyIterators() {
447 for (std::set
<TransactionIterator
*>::iterator i
= iterators_
.begin();
448 i
!= iterators_
.end();
450 TransactionIterator
* transaction_iterator
= *i
;
451 transaction_iterator
->DataChanged();
455 scoped_ptr
<LevelDBDirectTransaction
> LevelDBDirectTransaction::Create(
456 LevelDBDatabase
* db
) {
457 return make_scoped_ptr(new LevelDBDirectTransaction(db
));
460 LevelDBDirectTransaction::LevelDBDirectTransaction(LevelDBDatabase
* db
)
461 : db_(db
), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {}
463 LevelDBDirectTransaction::~LevelDBDirectTransaction() {
464 write_batch_
->Clear();
467 void LevelDBDirectTransaction::Put(const StringPiece
& key
,
468 const std::string
* value
) {
470 write_batch_
->Put(key
, *value
);
473 leveldb::Status
LevelDBDirectTransaction::Get(const StringPiece
& key
,
479 leveldb::Status s
= db_
->Get(key
, value
, found
);
480 DCHECK(s
.ok() || !*found
);
484 void LevelDBDirectTransaction::Remove(const StringPiece
& key
) {
486 write_batch_
->Remove(key
);
489 leveldb::Status
LevelDBDirectTransaction::Commit() {
492 leveldb::Status s
= db_
->Write(*write_batch_
);
495 write_batch_
->Clear();
500 } // namespace content