Cast: Skip receiver log messages with time delta that can't be encoded.
[chromium-blink-merge.git] / content / browser / indexed_db / leveldb / leveldb_transaction.cc
blob67d4cdbfd048222b017386cf0bd08c685d66153c
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;
14 namespace content {
16 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db)
17 : db_(db),
18 snapshot_(db),
19 comparator_(db->Comparator()),
20 data_comparator_(comparator_),
21 data_(data_comparator_),
22 finished_(false) {}
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) {
29 delete it->second;
31 data_.clear();
34 LevelDBTransaction::~LevelDBTransaction() { Clear(); }
36 void LevelDBTransaction::Set(const StringPiece& key,
37 std::string* value,
38 bool deleted) {
39 DCHECK(!finished_);
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;
48 NotifyIterators();
49 return;
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) {
61 std::string empty;
62 Set(key, &empty, true);
65 leveldb::Status LevelDBTransaction::Get(const StringPiece& key,
66 std::string* value,
67 bool* found) {
68 *found = false;
69 DCHECK(!finished_);
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;
78 *found = true;
79 return leveldb::Status::OK();
82 leveldb::Status s = db_->Get(key, value, found, &snapshot_);
83 if (!s.ok())
84 DCHECK(!*found);
85 return s;
88 leveldb::Status LevelDBTransaction::Commit() {
89 DCHECK(!finished_);
91 if (data_.empty()) {
92 finished_ = true;
93 return leveldb::Status::OK();
96 scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
98 for (DataType::iterator iterator = data_.begin(); iterator != data_.end();
99 ++iterator) {
100 if (!iterator->second->deleted)
101 write_batch->Put(iterator->first, iterator->second->value);
102 else
103 write_batch->Remove(iterator->first);
106 leveldb::Status s = db_->Write(*write_batch);
107 if (s.ok()) {
108 Clear();
109 finished_ = true;
111 return s;
114 void LevelDBTransaction::Rollback() {
115 DCHECK(!finished_);
116 finished_ = true;
117 Clear();
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())
136 --iterator_;
139 void LevelDBTransaction::DataIterator::Seek(const StringPiece& target) {
140 iterator_ = data_->lower_bound(target);
143 void LevelDBTransaction::DataIterator::Next() {
144 DCHECK(IsValid());
145 ++iterator_;
148 void LevelDBTransaction::DataIterator::Prev() {
149 DCHECK(IsValid());
150 if (iterator_ != data_->begin())
151 --iterator_;
152 else
153 iterator_ = data_->end();
156 StringPiece LevelDBTransaction::DataIterator::Key() const {
157 DCHECK(IsValid());
158 return iterator_->first;
161 StringPiece LevelDBTransaction::DataIterator::Value() const {
162 DCHECK(IsValid());
163 DCHECK(!IsDeleted());
164 return iterator_->second->value;
167 bool LevelDBTransaction::DataIterator::IsDeleted() const {
168 DCHECK(IsValid());
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_)),
190 current_(0),
191 direction_(FORWARD),
192 data_changed_(false) {
193 transaction_->RegisterIterator(this);
196 LevelDBTransaction::TransactionIterator::~TransactionIterator() {
197 transaction_->UnregisterIterator(this);
200 bool LevelDBTransaction::TransactionIterator::IsValid() const {
201 return !!current_;
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() {
223 DCHECK(IsValid());
224 if (data_changed_)
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().
239 non_current->Next();
241 DCHECK(!non_current->IsValid() ||
242 comparator_->Compare(non_current->Key(), Key()) > 0);
244 direction_ = FORWARD;
247 current_->Next();
248 HandleConflictsAndDeletes();
249 SetCurrentIteratorToSmallestKey();
252 void LevelDBTransaction::TransactionIterator::Prev() {
253 DCHECK(IsValid());
254 if (data_changed_)
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.
270 non_current->Prev();
271 } else {
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;
281 current_->Prev();
282 HandleConflictsAndDeletes();
283 SetCurrentIteratorToLargestKey();
286 StringPiece LevelDBTransaction::TransactionIterator::Key() const {
287 DCHECK(IsValid());
288 if (data_changed_)
289 RefreshDataIterator();
290 return current_->Key();
293 StringPiece LevelDBTransaction::TransactionIterator::Value() const {
294 DCHECK(IsValid());
295 if (data_changed_)
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_) {
310 return;
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();
324 } else {
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() {
343 bool loop = true;
345 while (loop) {
346 loop = false;
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();
354 else
355 db_iterator_->Prev();
358 // Skip over delete markers in the data iterator until it catches up with
359 // the db iterator.
360 if (data_iterator_->IsValid() && data_iterator_->IsDeleted()) {
361 if (direction_ == FORWARD &&
362 (!db_iterator_->IsValid() || DataIteratorIsLower())) {
363 data_iterator_->Next();
364 loop = true;
365 } else if (direction_ == REVERSE &&
366 (!db_iterator_->IsValid() || DataIteratorIsHigher())) {
367 data_iterator_->Prev();
368 loop = true;
374 void
375 LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
376 LevelDBIterator* smallest = 0;
378 if (data_iterator_->IsValid())
379 smallest = data_iterator_.get();
381 if (db_iterator_->IsValid()) {
382 if (!smallest ||
383 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0)
384 smallest = db_iterator_.get();
387 current_ = smallest;
390 void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() {
391 LevelDBIterator* largest = 0;
393 if (data_iterator_->IsValid())
394 largest = data_iterator_.get();
396 if (db_iterator_->IsValid()) {
397 if (!largest ||
398 comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0)
399 largest = db_iterator_.get();
402 current_ = largest;
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();
418 ++i) {
419 TransactionIterator* transaction_iterator = *i;
420 transaction_iterator->DataChanged();
424 scoped_ptr<LevelDBWriteOnlyTransaction> LevelDBWriteOnlyTransaction::Create(
425 LevelDBDatabase* db) {
426 return make_scoped_ptr(new LevelDBWriteOnlyTransaction(db));
429 LevelDBWriteOnlyTransaction::LevelDBWriteOnlyTransaction(LevelDBDatabase* db)
430 : db_(db), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {}
432 LevelDBWriteOnlyTransaction::~LevelDBWriteOnlyTransaction() {
433 write_batch_->Clear();
436 void LevelDBWriteOnlyTransaction::Remove(const StringPiece& key) {
437 DCHECK(!finished_);
438 write_batch_->Remove(key);
441 leveldb::Status LevelDBWriteOnlyTransaction::Commit() {
442 DCHECK(!finished_);
444 leveldb::Status s = db_->Write(*write_batch_);
445 if (s.ok()) {
446 finished_ = true;
447 write_batch_->Clear();
449 return s;
452 } // namespace content