OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 5 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 8 #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
9 #include "content/browser/indexed_db/leveldb/leveldb_write_batch.h" | 9 #include "content/browser/indexed_db/leveldb/leveldb_write_batch.h" |
10 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 10 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
11 | 11 |
12 using base::StringPiece; | 12 using base::StringPiece; |
13 | 13 |
14 namespace content { | 14 namespace content { |
15 | 15 |
16 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db) | 16 LevelDBTransaction::LevelDBTransaction(LevelDBDatabase* db) |
17 : db_(db), snapshot_(db), comparator_(db->Comparator()), finished_(false) { | 17 : db_(db), |
18 tree_.abstractor().comparator_ = comparator_; | 18 snapshot_(db), |
19 } | 19 comparator_(db->Comparator()), |
20 tree_comparator_(comparator_), | |
21 tree_(tree_comparator_), | |
22 finished_(false) {} | |
20 | 23 |
21 LevelDBTransaction::AVLTreeNode::AVLTreeNode() {} | 24 LevelDBTransaction::TreeNode::TreeNode() : deleted(false) {} |
22 LevelDBTransaction::AVLTreeNode::~AVLTreeNode() {} | 25 LevelDBTransaction::TreeNode::~TreeNode() {} |
23 | 26 |
24 void LevelDBTransaction::ClearTree() { | 27 void LevelDBTransaction::ClearTree() { |
25 TreeType::Iterator iterator; | 28 for (TreeType::iterator it = tree_.begin(); it != tree_.end(); ++it) { |
26 iterator.StartIterLeast(&tree_); | 29 delete it->second; |
27 | |
28 std::vector<AVLTreeNode*> nodes; | |
29 | |
30 while (*iterator) { | |
31 nodes.push_back(*iterator); | |
32 ++iterator; | |
33 } | 30 } |
34 tree_.Purge(); | 31 tree_.clear(); |
35 | |
36 for (size_t i = 0; i < nodes.size(); ++i) | |
37 delete nodes[i]; | |
38 } | 32 } |
39 | 33 |
40 LevelDBTransaction::~LevelDBTransaction() { ClearTree(); } | 34 LevelDBTransaction::~LevelDBTransaction() { ClearTree(); } |
41 | 35 |
42 void LevelDBTransaction::Set(const StringPiece& key, | 36 void LevelDBTransaction::Set(const StringPiece& key, |
43 std::string* value, | 37 std::string* value, |
44 bool deleted) { | 38 bool deleted) { |
45 DCHECK(!finished_); | 39 DCHECK(!finished_); |
46 bool new_node = false; | 40 std::string string_key(key.begin(), key.end() - key.begin()); |
47 AVLTreeNode* node = tree_.Search(key); | 41 TreeType::iterator it = tree_.find(string_key); |
48 | 42 |
49 if (!node) { | 43 if (it == tree_.end()) { |
50 node = new AVLTreeNode; | 44 TreeNode* node = new TreeNode(); |
51 node->key = key.as_string(); | 45 node->value.swap(*value); |
52 tree_.Insert(node); | 46 node->deleted = deleted; |
53 new_node = true; | 47 tree_[string_key] = node; |
48 NotifyIteratorsOfTreeChange(); | |
49 return; | |
54 } | 50 } |
55 node->value.swap(*value); | |
56 node->deleted = deleted; | |
57 | 51 |
58 if (new_node) | 52 it->second->value.swap(*value); |
59 NotifyIteratorsOfTreeChange(); | 53 it->second->deleted = deleted; |
60 } | 54 } |
61 | 55 |
62 void LevelDBTransaction::Put(const StringPiece& key, std::string* value) { | 56 void LevelDBTransaction::Put(const StringPiece& key, std::string* value) { |
63 Set(key, value, false); | 57 Set(key, value, false); |
64 } | 58 } |
65 | 59 |
66 void LevelDBTransaction::Remove(const StringPiece& key) { | 60 void LevelDBTransaction::Remove(const StringPiece& key) { |
67 std::string empty; | 61 std::string empty; |
68 Set(key, &empty, true); | 62 Set(key, &empty, true); |
69 } | 63 } |
70 | 64 |
71 bool LevelDBTransaction::Get(const StringPiece& key, | 65 bool LevelDBTransaction::Get(const StringPiece& key, |
72 std::string* value, | 66 std::string* value, |
73 bool* found) { | 67 bool* found) { |
74 *found = false; | 68 *found = false; |
75 DCHECK(!finished_); | 69 DCHECK(!finished_); |
76 AVLTreeNode* node = tree_.Search(key); | 70 std::string string_key(key.begin(), key.end() - key.begin()); |
alecflett
2013/09/10 16:46:40
Not that this is particularly expensive, but can y
jsbell
2013/09/10 17:00:06
StringPiece doesn't own its storage, and map::find
jsbell
2013/09/10 21:29:36
That turned out to be tricky due to upstream calle
| |
71 TreeType::const_iterator it = tree_.find(string_key); | |
77 | 72 |
78 if (node) { | 73 if (it != tree_.end()) { |
79 if (node->deleted) | 74 if (it->second->deleted) |
80 return true; | 75 return true; |
81 | 76 |
82 *value = node->value; | 77 *value = it->second->value; |
alecflett
2013/09/10 16:46:40
it's too bad there's no way to swap or something h
jsbell
2013/09/10 17:00:06
Nope, since the the storage is owned by the tree a
| |
83 *found = true; | 78 *found = true; |
84 return true; | 79 return true; |
85 } | 80 } |
86 | 81 |
87 bool ok = db_->Get(key, value, found, &snapshot_); | 82 bool ok = db_->Get(key, value, found, &snapshot_); |
alecflett
2013/09/10 16:46:40
I guess you'd have to propagate the stringpiece st
jsbell
2013/09/10 17:00:06
... but if key is passed in as a string that's not
| |
88 if (!ok) { | 83 if (!ok) { |
89 DCHECK(!*found); | 84 DCHECK(!*found); |
90 return false; | 85 return false; |
91 } | 86 } |
92 return true; | 87 return true; |
93 } | 88 } |
94 | 89 |
95 bool LevelDBTransaction::Commit() { | 90 bool LevelDBTransaction::Commit() { |
96 DCHECK(!finished_); | 91 DCHECK(!finished_); |
97 | 92 |
98 if (tree_.IsEmpty()) { | 93 if (tree_.empty()) { |
99 finished_ = true; | 94 finished_ = true; |
100 return true; | 95 return true; |
101 } | 96 } |
102 | 97 |
103 scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create(); | 98 scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create(); |
104 | 99 |
105 TreeType::Iterator iterator; | 100 for (TreeType::iterator iterator = tree_.begin(); iterator != tree_.end(); |
106 iterator.StartIterLeast(&tree_); | 101 ++iterator) { |
107 | 102 if (!iterator->second->deleted) |
108 while (*iterator) { | 103 write_batch->Put(iterator->first, iterator->second->value); |
109 AVLTreeNode* node = *iterator; | |
110 if (!node->deleted) | |
111 write_batch->Put(node->key, node->value); | |
112 else | 104 else |
113 write_batch->Remove(node->key); | 105 write_batch->Remove(iterator->first); |
114 ++iterator; | |
115 } | 106 } |
116 | 107 |
117 if (!db_->Write(*write_batch)) | 108 if (!db_->Write(*write_batch)) |
118 return false; | 109 return false; |
119 | 110 |
120 ClearTree(); | 111 ClearTree(); |
121 finished_ = true; | 112 finished_ = true; |
122 return true; | 113 return true; |
123 } | 114 } |
124 | 115 |
125 void LevelDBTransaction::Rollback() { | 116 void LevelDBTransaction::Rollback() { |
126 DCHECK(!finished_); | 117 DCHECK(!finished_); |
127 finished_ = true; | 118 finished_ = true; |
128 ClearTree(); | 119 ClearTree(); |
129 } | 120 } |
130 | 121 |
131 scoped_ptr<LevelDBIterator> LevelDBTransaction::CreateIterator() { | 122 scoped_ptr<LevelDBIterator> LevelDBTransaction::CreateIterator() { |
132 return TransactionIterator::Create(this).PassAs<LevelDBIterator>(); | 123 return TransactionIterator::Create(this).PassAs<LevelDBIterator>(); |
133 } | 124 } |
134 | 125 |
135 scoped_ptr<LevelDBTransaction::TreeIterator> | 126 scoped_ptr<LevelDBTransaction::TreeIterator> |
136 LevelDBTransaction::TreeIterator::Create(LevelDBTransaction* transaction) { | 127 LevelDBTransaction::TreeIterator::Create(LevelDBTransaction* transaction) { |
137 return make_scoped_ptr(new TreeIterator(transaction)); | 128 return make_scoped_ptr(new TreeIterator(transaction)); |
138 } | 129 } |
139 | 130 |
140 bool LevelDBTransaction::TreeIterator::IsValid() const { return !!*iterator_; } | 131 bool LevelDBTransaction::TreeIterator::IsValid() const { |
132 return iterator_ != tree_->end(); | |
133 } | |
141 | 134 |
142 void LevelDBTransaction::TreeIterator::SeekToLast() { | 135 void LevelDBTransaction::TreeIterator::SeekToLast() { |
143 iterator_.StartIterGreatest(tree_); | 136 iterator_ = tree_->end(); |
137 if (iterator_ != tree_->begin()) | |
138 --iterator_; | |
139 | |
144 if (IsValid()) | 140 if (IsValid()) |
145 key_ = (*iterator_)->key; | 141 key_ = iterator_->first; |
146 } | 142 } |
147 | 143 |
148 void LevelDBTransaction::TreeIterator::Seek(const StringPiece& target) { | 144 void LevelDBTransaction::TreeIterator::Seek(const StringPiece& target) { |
149 iterator_.StartIter(tree_, target, TreeType::EQUAL); | 145 std::string key(target.begin(), target.end() - target.begin()); |
alecflett
2013/09/10 16:46:40
copying on a seek seems bad?
jsbell
2013/09/10 17:00:06
I'll look at changing this API here to take a cons
| |
150 if (!IsValid()) | 146 |
151 iterator_.StartIter(tree_, target, TreeType::GREATER); | 147 iterator_ = tree_->find(key); |
148 if (!IsValid()) { | |
149 TreeNode dummy; | |
ericu
2013/09/10 01:00:41
How about map::lower_bound or map::equal_range?
jsbell
2013/09/10 17:00:06
lower_bound should work - it looks like exactly wh
| |
150 std::pair<TreeType::iterator, bool> position = | |
151 tree_->insert(make_pair(key, &dummy)); | |
152 iterator_ = position.first; | |
153 ++iterator_; | |
154 tree_->erase(position.first); | |
155 } | |
152 | 156 |
153 if (IsValid()) | 157 if (IsValid()) |
154 key_ = (*iterator_)->key; | 158 key_ = iterator_->first; |
155 } | 159 } |
156 | 160 |
157 void LevelDBTransaction::TreeIterator::Next() { | 161 void LevelDBTransaction::TreeIterator::Next() { |
158 DCHECK(IsValid()); | 162 DCHECK(IsValid()); |
159 ++iterator_; | 163 ++iterator_; |
160 if (IsValid()) { | 164 if (IsValid()) { |
161 DCHECK_GE(transaction_->comparator_->Compare((*iterator_)->key, key_), 0); | 165 DCHECK_GE(transaction_->comparator_->Compare(iterator_->first, key_), 0); |
162 key_ = (*iterator_)->key; | 166 key_ = iterator_->first; |
163 } | 167 } |
164 } | 168 } |
165 | 169 |
166 void LevelDBTransaction::TreeIterator::Prev() { | 170 void LevelDBTransaction::TreeIterator::Prev() { |
167 DCHECK(IsValid()); | 171 DCHECK(IsValid()); |
168 --iterator_; | 172 if (iterator_ != tree_->begin()) |
173 --iterator_; | |
174 else | |
175 iterator_ = tree_->end(); | |
169 if (IsValid()) { | 176 if (IsValid()) { |
170 DCHECK_LT(tree_->abstractor().comparator_->Compare((*iterator_)->key, key_), | 177 DCHECK_LT(transaction_->comparator_->Compare(iterator_->first, key_), 0); |
171 0); | 178 key_ = iterator_->first; |
172 key_ = (*iterator_)->key; | |
173 } | 179 } |
174 } | 180 } |
175 | 181 |
176 StringPiece LevelDBTransaction::TreeIterator::Key() const { | 182 StringPiece LevelDBTransaction::TreeIterator::Key() const { |
177 DCHECK(IsValid()); | 183 DCHECK(IsValid()); |
178 return key_; | 184 return key_; |
179 } | 185 } |
180 | 186 |
181 StringPiece LevelDBTransaction::TreeIterator::Value() const { | 187 StringPiece LevelDBTransaction::TreeIterator::Value() const { |
182 DCHECK(IsValid()); | 188 DCHECK(IsValid()); |
183 DCHECK(!IsDeleted()); | 189 DCHECK(!IsDeleted()); |
184 return (*iterator_)->value; | 190 return iterator_->second->value; |
185 } | 191 } |
186 | 192 |
187 bool LevelDBTransaction::TreeIterator::IsDeleted() const { | 193 bool LevelDBTransaction::TreeIterator::IsDeleted() const { |
188 DCHECK(IsValid()); | 194 DCHECK(IsValid()); |
189 return (*iterator_)->deleted; | 195 return iterator_->second->deleted; |
190 } | 196 } |
191 | 197 |
192 void LevelDBTransaction::TreeIterator::Reset() { | 198 void LevelDBTransaction::TreeIterator::Reset() { |
193 DCHECK(IsValid()); | 199 DCHECK(IsValid()); |
194 iterator_.StartIter(tree_, key_, TreeType::EQUAL); | 200 iterator_ = tree_->find(key_); |
195 DCHECK(IsValid()); | 201 DCHECK(IsValid()); |
196 } | 202 } |
197 | 203 |
198 LevelDBTransaction::TreeIterator::~TreeIterator() {} | 204 LevelDBTransaction::TreeIterator::~TreeIterator() {} |
199 | 205 |
200 LevelDBTransaction::TreeIterator::TreeIterator(LevelDBTransaction* transaction) | 206 LevelDBTransaction::TreeIterator::TreeIterator(LevelDBTransaction* transaction) |
201 : tree_(&transaction->tree_), transaction_(transaction) {} | 207 : tree_(&transaction->tree_), |
208 iterator_(tree_->end()), | |
209 transaction_(transaction) {} | |
202 | 210 |
203 scoped_ptr<LevelDBTransaction::TransactionIterator> | 211 scoped_ptr<LevelDBTransaction::TransactionIterator> |
204 LevelDBTransaction::TransactionIterator::Create( | 212 LevelDBTransaction::TransactionIterator::Create( |
205 scoped_refptr<LevelDBTransaction> transaction) { | 213 scoped_refptr<LevelDBTransaction> transaction) { |
206 return make_scoped_ptr(new TransactionIterator(transaction)); | 214 return make_scoped_ptr(new TransactionIterator(transaction)); |
207 } | 215 } |
208 | 216 |
209 LevelDBTransaction::TransactionIterator::TransactionIterator( | 217 LevelDBTransaction::TransactionIterator::TransactionIterator( |
210 scoped_refptr<LevelDBTransaction> transaction) | 218 scoped_refptr<LevelDBTransaction> transaction) |
211 : transaction_(transaction), | 219 : transaction_(transaction), |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 | 475 |
468 if (!db_->Write(*write_batch_)) | 476 if (!db_->Write(*write_batch_)) |
469 return false; | 477 return false; |
470 | 478 |
471 finished_ = true; | 479 finished_ = true; |
472 write_batch_->Clear(); | 480 write_batch_->Clear(); |
473 return true; | 481 return true; |
474 } | 482 } |
475 | 483 |
476 } // namespace content | 484 } // namespace content |
OLD | NEW |