leveldb_transaction.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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.
4
5#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
6
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"
11
12using base::StringPiece;
13
14namespace content {
15
16LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db)
17    : db_(db), snapshot_(db), comparator_(db->Comparator()), finished_(false) {
18  tree_.abstractor().comparator_ = comparator_;
19}
20
21LevelDBTransaction::AVLTreeNode::AVLTreeNode() {}
22LevelDBTransaction::AVLTreeNode::~AVLTreeNode() {}
23
24void LevelDBTransaction::ClearTree() {
25  TreeType::Iterator iterator;
26  iterator.StartIterLeast(&tree_);
27
28  std::vector<AVLTreeNode*> nodes;
29
30  while (*iterator) {
31    nodes.push_back(*iterator);
32    ++iterator;
33  }
34  tree_.Purge();
35
36  for (size_t i = 0; i < nodes.size(); ++i)
37    delete nodes[i];
38}
39
40LevelDBTransaction::~LevelDBTransaction() { ClearTree(); }
41
42void LevelDBTransaction::Set(const StringPiece& key,
43                             std::string* value,
44                             bool deleted) {
45  DCHECK(!finished_);
46  bool new_node = false;
47  AVLTreeNode* node = tree_.Search(key);
48
49  if (!node) {
50    node = new AVLTreeNode;
51    node->key = key.as_string();
52    tree_.Insert(node);
53    new_node = true;
54  }
55  node->value.swap(*value);
56  node->deleted = deleted;
57
58  if (new_node)
59    NotifyIteratorsOfTreeChange();
60}
61
62void LevelDBTransaction::Put(const StringPiece& key, std::string* value) {
63  Set(key, value, false);
64}
65
66void LevelDBTransaction::Remove(const StringPiece& key) {
67  std::string empty;
68  Set(key, &empty, true);
69}
70
71bool LevelDBTransaction::Get(const StringPiece& key,
72                             std::string* value,
73                             bool* found) {
74  *found = false;
75  DCHECK(!finished_);
76  AVLTreeNode* node = tree_.Search(key);
77
78  if (node) {
79    if (node->deleted)
80      return true;
81
82    *value = node->value;
83    *found = true;
84    return true;
85  }
86
87  bool ok = db_->Get(key, value, found, &snapshot_);
88  if (!ok) {
89    DCHECK(!*found);
90    return false;
91  }
92  return true;
93}
94
95bool LevelDBTransaction::Commit() {
96  DCHECK(!finished_);
97
98  if (tree_.IsEmpty()) {
99    finished_ = true;
100    return true;
101  }
102
103  scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
104
105  TreeType::Iterator iterator;
106  iterator.StartIterLeast(&tree_);
107
108  while (*iterator) {
109    AVLTreeNode* node = *iterator;
110    if (!node->deleted)
111      write_batch->Put(node->key, node->value);
112    else
113      write_batch->Remove(node->key);
114    ++iterator;
115  }
116
117  if (!db_->Write(*write_batch))
118    return false;
119
120  ClearTree();
121  finished_ = true;
122  return true;
123}
124
125void LevelDBTransaction::Rollback() {
126  DCHECK(!finished_);
127  finished_ = true;
128  ClearTree();
129}
130
131scoped_ptr<LevelDBIterator> LevelDBTransaction::CreateIterator() {
132  return TransactionIterator::Create(this).PassAs<LevelDBIterator>();
133}
134
135scoped_ptr<LevelDBTransaction::TreeIterator>
136LevelDBTransaction::TreeIterator::Create(LevelDBTransaction* transaction) {
137  return make_scoped_ptr(new TreeIterator(transaction));
138}
139
140bool LevelDBTransaction::TreeIterator::IsValid() const { return !!*iterator_; }
141
142void LevelDBTransaction::TreeIterator::SeekToLast() {
143  iterator_.StartIterGreatest(tree_);
144  if (IsValid())
145    key_ = (*iterator_)->key;
146}
147
148void LevelDBTransaction::TreeIterator::Seek(const StringPiece& target) {
149  iterator_.StartIter(tree_, target, TreeType::EQUAL);
150  if (!IsValid())
151    iterator_.StartIter(tree_, target, TreeType::GREATER);
152
153  if (IsValid())
154    key_ = (*iterator_)->key;
155}
156
157void LevelDBTransaction::TreeIterator::Next() {
158  DCHECK(IsValid());
159  ++iterator_;
160  if (IsValid()) {
161    DCHECK_GE(transaction_->comparator_->Compare((*iterator_)->key, key_), 0);
162    key_ = (*iterator_)->key;
163  }
164}
165
166void LevelDBTransaction::TreeIterator::Prev() {
167  DCHECK(IsValid());
168  --iterator_;
169  if (IsValid()) {
170    DCHECK_LT(tree_->abstractor().comparator_->Compare((*iterator_)->key, key_),
171              0);
172    key_ = (*iterator_)->key;
173  }
174}
175
176StringPiece LevelDBTransaction::TreeIterator::Key() const {
177  DCHECK(IsValid());
178  return key_;
179}
180
181StringPiece LevelDBTransaction::TreeIterator::Value() const {
182  DCHECK(IsValid());
183  DCHECK(!IsDeleted());
184  return (*iterator_)->value;
185}
186
187bool LevelDBTransaction::TreeIterator::IsDeleted() const {
188  DCHECK(IsValid());
189  return (*iterator_)->deleted;
190}
191
192void LevelDBTransaction::TreeIterator::Reset() {
193  DCHECK(IsValid());
194  iterator_.StartIter(tree_, key_, TreeType::EQUAL);
195  DCHECK(IsValid());
196}
197
198LevelDBTransaction::TreeIterator::~TreeIterator() {}
199
200LevelDBTransaction::TreeIterator::TreeIterator(LevelDBTransaction* transaction)
201    : tree_(&transaction->tree_), transaction_(transaction) {}
202
203scoped_ptr<LevelDBTransaction::TransactionIterator>
204LevelDBTransaction::TransactionIterator::Create(
205    scoped_refptr<LevelDBTransaction> transaction) {
206  return make_scoped_ptr(new TransactionIterator(transaction));
207}
208
209LevelDBTransaction::TransactionIterator::TransactionIterator(
210    scoped_refptr<LevelDBTransaction> transaction)
211    : transaction_(transaction),
212      comparator_(transaction_->comparator_),
213      tree_iterator_(TreeIterator::Create(transaction_.get())),
214      db_iterator_(transaction_->db_->CreateIterator(&transaction_->snapshot_)),
215      current_(0),
216      direction_(FORWARD),
217      tree_changed_(false) {
218  transaction_->RegisterIterator(this);
219}
220
221LevelDBTransaction::TransactionIterator::~TransactionIterator() {
222  transaction_->UnregisterIterator(this);
223}
224
225bool LevelDBTransaction::TransactionIterator::IsValid() const {
226  return !!current_;
227}
228
229void LevelDBTransaction::TransactionIterator::SeekToLast() {
230  tree_iterator_->SeekToLast();
231  db_iterator_->SeekToLast();
232  direction_ = REVERSE;
233
234  HandleConflictsAndDeletes();
235  SetCurrentIteratorToLargestKey();
236}
237
238void LevelDBTransaction::TransactionIterator::Seek(const StringPiece& target) {
239  tree_iterator_->Seek(target);
240  db_iterator_->Seek(target);
241  direction_ = FORWARD;
242
243  HandleConflictsAndDeletes();
244  SetCurrentIteratorToSmallestKey();
245}
246
247void LevelDBTransaction::TransactionIterator::Next() {
248  DCHECK(IsValid());
249  if (tree_changed_)
250    RefreshTreeIterator();
251
252  if (direction_ != FORWARD) {
253    // Ensure the non-current iterator is positioned after Key().
254
255    LevelDBIterator* non_current = (current_ == db_iterator_.get())
256                                       ? tree_iterator_.get()
257                                       : db_iterator_.get();
258
259    non_current->Seek(Key());
260    if (non_current->IsValid() &&
261        !comparator_->Compare(non_current->Key(), Key()))
262      non_current->Next();  // Take an extra step so the non-current key is
263                            // strictly greater than Key().
264
265    DCHECK(!non_current->IsValid() ||
266           comparator_->Compare(non_current->Key(), Key()) > 0);
267
268    direction_ = FORWARD;
269  }
270
271  current_->Next();
272  HandleConflictsAndDeletes();
273  SetCurrentIteratorToSmallestKey();
274}
275
276void LevelDBTransaction::TransactionIterator::Prev() {
277  DCHECK(IsValid());
278  if (tree_changed_)
279    RefreshTreeIterator();
280
281  if (direction_ != REVERSE) {
282    // Ensure the non-current iterator is positioned before Key().
283
284    LevelDBIterator* non_current = (current_ == db_iterator_.get())
285                                       ? tree_iterator_.get()
286                                       : db_iterator_.get();
287
288    non_current->Seek(Key());
289    if (non_current->IsValid()) {
290      // Iterator is at first entry >= Key().
291      // Step back once to entry < key.
292      // This is why we don't check for the keys being the same before
293      // stepping, like we do in Next() above.
294      non_current->Prev();
295    } else {
296      non_current->SeekToLast();  // Iterator has no entries >= Key(). Position
297                                  // at last entry.
298    }
299    DCHECK(!non_current->IsValid() ||
300           comparator_->Compare(non_current->Key(), Key()) < 0);
301
302    direction_ = REVERSE;
303  }
304
305  current_->Prev();
306  HandleConflictsAndDeletes();
307  SetCurrentIteratorToLargestKey();
308}
309
310StringPiece LevelDBTransaction::TransactionIterator::Key() const {
311  DCHECK(IsValid());
312  if (tree_changed_)
313    RefreshTreeIterator();
314  return current_->Key();
315}
316
317StringPiece LevelDBTransaction::TransactionIterator::Value() const {
318  DCHECK(IsValid());
319  if (tree_changed_)
320    RefreshTreeIterator();
321  return current_->Value();
322}
323
324void LevelDBTransaction::TransactionIterator::TreeChanged() {
325  tree_changed_ = true;
326}
327
328void LevelDBTransaction::TransactionIterator::RefreshTreeIterator() const {
329  DCHECK(tree_changed_);
330
331  tree_changed_ = false;
332
333  if (tree_iterator_->IsValid() && tree_iterator_.get() == current_) {
334    tree_iterator_->Reset();
335    return;
336  }
337
338  if (db_iterator_->IsValid()) {
339    // There could be new nodes in the tree that we should iterate over.
340
341    if (direction_ == FORWARD) {
342      // Try to seek tree iterator to something greater than the db iterator.
343      tree_iterator_->Seek(db_iterator_->Key());
344      if (tree_iterator_->IsValid() &&
345          !comparator_->Compare(tree_iterator_->Key(), db_iterator_->Key()))
346        tree_iterator_->Next();  // If equal, take another step so the tree
347                                 // iterator is strictly greater.
348    } else {
349      // If going backward, seek to a key less than the db iterator.
350      DCHECK_EQ(REVERSE, direction_);
351      tree_iterator_->Seek(db_iterator_->Key());
352      if (tree_iterator_->IsValid())
353        tree_iterator_->Prev();
354    }
355  }
356}
357
358bool LevelDBTransaction::TransactionIterator::TreeIteratorIsLower() const {
359  return comparator_->Compare(tree_iterator_->Key(), db_iterator_->Key()) < 0;
360}
361
362bool LevelDBTransaction::TransactionIterator::TreeIteratorIsHigher() const {
363  return comparator_->Compare(tree_iterator_->Key(), db_iterator_->Key()) > 0;
364}
365
366void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() {
367  bool loop = true;
368
369  while (loop) {
370    loop = false;
371
372    if (tree_iterator_->IsValid() && db_iterator_->IsValid() &&
373        !comparator_->Compare(tree_iterator_->Key(), db_iterator_->Key())) {
374      // For equal keys, the tree iterator takes precedence, so move the
375      // database iterator another step.
376      if (direction_ == FORWARD)
377        db_iterator_->Next();
378      else
379        db_iterator_->Prev();
380    }
381
382    // Skip over delete markers in the tree iterator until it catches up with
383    // the db iterator.
384    if (tree_iterator_->IsValid() && tree_iterator_->IsDeleted()) {
385      if (direction_ == FORWARD &&
386          (!db_iterator_->IsValid() || TreeIteratorIsLower())) {
387        tree_iterator_->Next();
388        loop = true;
389      } else if (direction_ == REVERSE &&
390                 (!db_iterator_->IsValid() || TreeIteratorIsHigher())) {
391        tree_iterator_->Prev();
392        loop = true;
393      }
394    }
395  }
396}
397
398void
399LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() {
400  LevelDBIterator* smallest = 0;
401
402  if (tree_iterator_->IsValid())
403    smallest = tree_iterator_.get();
404
405  if (db_iterator_->IsValid()) {
406    if (!smallest ||
407        comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0)
408      smallest = db_iterator_.get();
409  }
410
411  current_ = smallest;
412}
413
414void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() {
415  LevelDBIterator* largest = 0;
416
417  if (tree_iterator_->IsValid())
418    largest = tree_iterator_.get();
419
420  if (db_iterator_->IsValid()) {
421    if (!largest ||
422        comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0)
423      largest = db_iterator_.get();
424  }
425
426  current_ = largest;
427}
428
429void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) {
430  DCHECK(iterators_.find(iterator) == iterators_.end());
431  iterators_.insert(iterator);
432}
433
434void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) {
435  DCHECK(iterators_.find(iterator) != iterators_.end());
436  iterators_.erase(iterator);
437}
438
439void LevelDBTransaction::NotifyIteratorsOfTreeChange() {
440  for (std::set<TransactionIterator*>::iterator i = iterators_.begin();
441       i != iterators_.end();
442       ++i) {
443    TransactionIterator* transaction_iterator = *i;
444    transaction_iterator->TreeChanged();
445  }
446}
447
448scoped_ptr<LevelDBWriteOnlyTransaction> LevelDBWriteOnlyTransaction::Create(
449    LevelDBDatabase* db) {
450  return make_scoped_ptr(new LevelDBWriteOnlyTransaction(db));
451}
452
453LevelDBWriteOnlyTransaction::LevelDBWriteOnlyTransaction(LevelDBDatabase* db)
454    : db_(db), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {}
455
456LevelDBWriteOnlyTransaction::~LevelDBWriteOnlyTransaction() {
457  write_batch_->Clear();
458}
459
460void LevelDBWriteOnlyTransaction::Remove(const StringPiece& key) {
461  DCHECK(!finished_);
462  write_batch_->Remove(key);
463}
464
465bool LevelDBWriteOnlyTransaction::Commit() {
466  DCHECK(!finished_);
467
468  if (!db_->Write(*write_batch_))
469    return false;
470
471  finished_ = true;
472  write_batch_->Clear();
473  return true;
474}
475
476}  // namespace content
477