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 "content/browser/indexed_db/leveldb/leveldb_database.h"
9 #include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
10 #include "third_party/leveldatabase/src/include/leveldb/db.h"
12 using base::StringPiece
;
16 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase
* db
)
19 comparator_(db
->Comparator()),
20 data_comparator_(comparator_
),
21 data_(data_comparator_
),
24 LevelDBTransaction::Record::Record() : deleted(false) {}
25 LevelDBTransaction::Record::~Record() {}
27 void LevelDBTransaction::Clear() {
28 for (DataType::iterator it
= data_
.begin(); it
!= data_
.end(); ++it
) {
34 LevelDBTransaction::~LevelDBTransaction() { Clear(); }
36 void LevelDBTransaction::Set(const StringPiece
& key
,
40 DataType::iterator it
= data_
.find(key
);
42 if (it
== data_
.end()) {
43 Record
* record
= new Record();
44 record
->key
.assign(key
.begin(), key
.end() - key
.begin());
45 record
->value
.swap(*value
);
46 record
->deleted
= deleted
;
47 data_
[record
->key
] = record
;
52 it
->second
->value
.swap(*value
);
53 it
->second
->deleted
= deleted
;
56 void LevelDBTransaction::Put(const StringPiece
& key
, std::string
* value
) {
57 Set(key
, value
, false);
60 void LevelDBTransaction::Remove(const StringPiece
& key
) {
62 Set(key
, &empty
, true);
65 leveldb::Status
LevelDBTransaction::Get(const StringPiece
& key
,
70 std::string
string_key(key
.begin(), key
.end() - key
.begin());
71 DataType::const_iterator it
= data_
.find(string_key
);
73 if (it
!= data_
.end()) {
74 if (it
->second
->deleted
)
75 return leveldb::Status::OK();
77 *value
= it
->second
->value
;
79 return leveldb::Status::OK();
82 leveldb::Status s
= db_
->Get(key
, value
, found
, &snapshot_
);
88 leveldb::Status
LevelDBTransaction::Commit() {
93 return leveldb::Status::OK();
96 scoped_ptr
<LevelDBWriteBatch
> write_batch
= LevelDBWriteBatch::Create();
98 for (DataType::iterator iterator
= data_
.begin(); iterator
!= data_
.end();
100 if (!iterator
->second
->deleted
)
101 write_batch
->Put(iterator
->first
, iterator
->second
->value
);
103 write_batch
->Remove(iterator
->first
);
106 leveldb::Status s
= db_
->Write(*write_batch
);
114 void LevelDBTransaction::Rollback() {
120 scoped_ptr
<LevelDBIterator
> LevelDBTransaction::CreateIterator() {
121 return TransactionIterator::Create(this).PassAs
<LevelDBIterator
>();
124 scoped_ptr
<LevelDBTransaction::DataIterator
>
125 LevelDBTransaction::DataIterator::Create(LevelDBTransaction
* transaction
) {
126 return make_scoped_ptr(new DataIterator(transaction
));
129 bool LevelDBTransaction::DataIterator::IsValid() const {
130 return iterator_
!= data_
->end();
133 void LevelDBTransaction::DataIterator::SeekToLast() {
134 iterator_
= data_
->end();
135 if (iterator_
!= data_
->begin())
139 void LevelDBTransaction::DataIterator::Seek(const StringPiece
& target
) {
140 iterator_
= data_
->lower_bound(target
);
143 void LevelDBTransaction::DataIterator::Next() {
148 void LevelDBTransaction::DataIterator::Prev() {
150 if (iterator_
!= data_
->begin())
153 iterator_
= data_
->end();
156 StringPiece
LevelDBTransaction::DataIterator::Key() const {
158 return iterator_
->first
;
161 StringPiece
LevelDBTransaction::DataIterator::Value() const {
163 DCHECK(!IsDeleted());
164 return iterator_
->second
->value
;
167 bool LevelDBTransaction::DataIterator::IsDeleted() const {
169 return iterator_
->second
->deleted
;
172 LevelDBTransaction::DataIterator::~DataIterator() {}
174 LevelDBTransaction::DataIterator::DataIterator(LevelDBTransaction
* transaction
)
175 : data_(&transaction
->data_
),
176 iterator_(data_
->end()) {}
178 scoped_ptr
<LevelDBTransaction::TransactionIterator
>
179 LevelDBTransaction::TransactionIterator::Create(
180 scoped_refptr
<LevelDBTransaction
> transaction
) {
181 return make_scoped_ptr(new TransactionIterator(transaction
));
184 LevelDBTransaction::TransactionIterator::TransactionIterator(
185 scoped_refptr
<LevelDBTransaction
> transaction
)
186 : transaction_(transaction
),
187 comparator_(transaction_
->comparator_
),
188 data_iterator_(DataIterator::Create(transaction_
.get())),
189 db_iterator_(transaction_
->db_
->CreateIterator(&transaction_
->snapshot_
)),
192 data_changed_(false) {
193 transaction_
->RegisterIterator(this);
196 LevelDBTransaction::TransactionIterator::~TransactionIterator() {
197 transaction_
->UnregisterIterator(this);
200 bool LevelDBTransaction::TransactionIterator::IsValid() const {
204 void LevelDBTransaction::TransactionIterator::SeekToLast() {
205 data_iterator_
->SeekToLast();
206 db_iterator_
->SeekToLast();
207 direction_
= REVERSE
;
209 HandleConflictsAndDeletes();
210 SetCurrentIteratorToLargestKey();
213 void LevelDBTransaction::TransactionIterator::Seek(const StringPiece
& target
) {
214 data_iterator_
->Seek(target
);
215 db_iterator_
->Seek(target
);
216 direction_
= FORWARD
;
218 HandleConflictsAndDeletes();
219 SetCurrentIteratorToSmallestKey();
222 void LevelDBTransaction::TransactionIterator::Next() {
225 RefreshDataIterator();
227 if (direction_
!= FORWARD
) {
228 // Ensure the non-current iterator is positioned after Key().
230 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
231 ? data_iterator_
.get()
232 : db_iterator_
.get();
234 non_current
->Seek(Key());
235 if (non_current
->IsValid() &&
236 !comparator_
->Compare(non_current
->Key(), Key())) {
237 // Take an extra step so the non-current key is
238 // strictly greater than Key().
241 DCHECK(!non_current
->IsValid() ||
242 comparator_
->Compare(non_current
->Key(), Key()) > 0);
244 direction_
= FORWARD
;
248 HandleConflictsAndDeletes();
249 SetCurrentIteratorToSmallestKey();
252 void LevelDBTransaction::TransactionIterator::Prev() {
255 RefreshDataIterator();
257 if (direction_
!= REVERSE
) {
258 // Ensure the non-current iterator is positioned before Key().
260 LevelDBIterator
* non_current
= (current_
== db_iterator_
.get())
261 ? data_iterator_
.get()
262 : db_iterator_
.get();
264 non_current
->Seek(Key());
265 if (non_current
->IsValid()) {
266 // Iterator is at first entry >= Key().
267 // Step back once to entry < key.
268 // This is why we don't check for the keys being the same before
269 // stepping, like we do in Next() above.
272 // Iterator has no entries >= Key(). Position at last entry.
273 non_current
->SeekToLast();
275 DCHECK(!non_current
->IsValid() ||
276 comparator_
->Compare(non_current
->Key(), Key()) < 0);
278 direction_
= REVERSE
;
282 HandleConflictsAndDeletes();
283 SetCurrentIteratorToLargestKey();
286 StringPiece
LevelDBTransaction::TransactionIterator::Key() const {
289 RefreshDataIterator();
290 return current_
->Key();
293 StringPiece
LevelDBTransaction::TransactionIterator::Value() const {
296 RefreshDataIterator();
297 return current_
->Value();
300 void LevelDBTransaction::TransactionIterator::DataChanged() {
301 data_changed_
= true;
304 void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const {
305 DCHECK(data_changed_
);
307 data_changed_
= false;
309 if (data_iterator_
->IsValid() && data_iterator_
.get() == current_
) {
313 if (db_iterator_
->IsValid()) {
314 // There could be new records in data that we should iterate over.
316 if (direction_
== FORWARD
) {
317 // Try to seek data iterator to something greater than the db iterator.
318 data_iterator_
->Seek(db_iterator_
->Key());
319 if (data_iterator_
->IsValid() &&
320 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
321 // If equal, take another step so the data iterator is strictly greater.
322 data_iterator_
->Next();
325 // If going backward, seek to a key less than the db iterator.
326 DCHECK_EQ(REVERSE
, direction_
);
327 data_iterator_
->Seek(db_iterator_
->Key());
328 if (data_iterator_
->IsValid())
329 data_iterator_
->Prev();
334 bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const {
335 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) < 0;
338 bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const {
339 return comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key()) > 0;
342 void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
348 if (data_iterator_
->IsValid() && db_iterator_
->IsValid() &&
349 !comparator_
->Compare(data_iterator_
->Key(), db_iterator_
->Key())) {
350 // For equal keys, the data iterator takes precedence, so move the
351 // database iterator another step.
352 if (direction_
== FORWARD
)
353 db_iterator_
->Next();
355 db_iterator_
->Prev();
358 // Skip over delete markers in the data iterator until it catches up with
360 if (data_iterator_
->IsValid() && data_iterator_
->IsDeleted()) {
361 if (direction_
== FORWARD
&&
362 (!db_iterator_
->IsValid() || DataIteratorIsLower())) {
363 data_iterator_
->Next();
365 } else if (direction_
== REVERSE
&&
366 (!db_iterator_
->IsValid() || DataIteratorIsHigher())) {
367 data_iterator_
->Prev();
375 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
376 LevelDBIterator
* smallest
= 0;
378 if (data_iterator_
->IsValid())
379 smallest
= data_iterator_
.get();
381 if (db_iterator_
->IsValid()) {
383 comparator_
->Compare(db_iterator_
->Key(), smallest
->Key()) < 0)
384 smallest
= db_iterator_
.get();
390 void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() {
391 LevelDBIterator
* largest
= 0;
393 if (data_iterator_
->IsValid())
394 largest
= data_iterator_
.get();
396 if (db_iterator_
->IsValid()) {
398 comparator_
->Compare(db_iterator_
->Key(), largest
->Key()) > 0)
399 largest
= db_iterator_
.get();
405 void LevelDBTransaction::RegisterIterator(TransactionIterator
* iterator
) {
406 DCHECK(iterators_
.find(iterator
) == iterators_
.end());
407 iterators_
.insert(iterator
);
410 void LevelDBTransaction::UnregisterIterator(TransactionIterator
* iterator
) {
411 DCHECK(iterators_
.find(iterator
) != iterators_
.end());
412 iterators_
.erase(iterator
);
415 void LevelDBTransaction::NotifyIterators() {
416 for (std::set
<TransactionIterator
*>::iterator i
= iterators_
.begin();
417 i
!= iterators_
.end();
419 TransactionIterator
* transaction_iterator
= *i
;
420 transaction_iterator
->DataChanged();
424 scoped_ptr
<LevelDBDirectTransaction
> LevelDBDirectTransaction::Create(
425 LevelDBDatabase
* db
) {
426 return make_scoped_ptr(new LevelDBDirectTransaction(db
));
429 LevelDBDirectTransaction::LevelDBDirectTransaction(LevelDBDatabase
* db
)
430 : db_(db
), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {}
432 LevelDBDirectTransaction::~LevelDBDirectTransaction() {
433 write_batch_
->Clear();
436 void LevelDBDirectTransaction::Put(const StringPiece
& key
,
437 const std::string
* value
) {
439 write_batch_
->Put(key
, *value
);
442 leveldb::Status
LevelDBDirectTransaction::Get(const StringPiece
& key
,
448 leveldb::Status s
= db_
->Get(key
, value
, found
);
449 DCHECK(s
.ok() || !*found
);
453 void LevelDBDirectTransaction::Remove(const StringPiece
& key
) {
455 write_batch_
->Remove(key
);
458 leveldb::Status
LevelDBDirectTransaction::Commit() {
461 leveldb::Status s
= db_
->Write(*write_batch_
);
464 write_batch_
->Clear();
469 } // namespace content