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