leveldb_transaction.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 65leveldb::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); 72 73 if (it != data_.end()) { 74 if (it->second->deleted) 75 return leveldb::Status::OK(); 76 77 *value = it->second->value; 78 *found = true; 79 return leveldb::Status::OK(); 80 } 81 82 leveldb::Status s = db_->Get(key, value, found, &snapshot_); 83 if (!s.ok()) 84 DCHECK(!*found); 85 return s; 86} 87 88leveldb::Status LevelDBTransaction::Commit() { 89 DCHECK(!finished_); 90 91 if (data_.empty()) { 92 finished_ = true; 93 return leveldb::Status::OK(); 94 } 95 96 scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create(); 97 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); 104 } 105 106 leveldb::Status s = db_->Write(*write_batch); 107 if (s.ok()) { 108 Clear(); 109 finished_ = true; 110 } 111 return s; 112} 113 114void LevelDBTransaction::Rollback() { 115 DCHECK(!finished_); 116 finished_ = true; 117 Clear(); 118} 119 120scoped_ptr<LevelDBIterator> LevelDBTransaction::CreateIterator() { 121 return TransactionIterator::Create(this).PassAs<LevelDBIterator>(); 122} 123 124scoped_ptr<LevelDBTransaction::DataIterator> 125LevelDBTransaction::DataIterator::Create(LevelDBTransaction* transaction) { 126 return make_scoped_ptr(new DataIterator(transaction)); 127} 128 129bool LevelDBTransaction::DataIterator::IsValid() const { 130 return iterator_ != data_->end(); 131} 132 133void LevelDBTransaction::DataIterator::SeekToLast() { 134 iterator_ = data_->end(); 135 if (iterator_ != data_->begin()) 136 --iterator_; 137} 138 139void LevelDBTransaction::DataIterator::Seek(const StringPiece& target) { 140 iterator_ = data_->lower_bound(target); 141} 142 143void LevelDBTransaction::DataIterator::Next() { 144 DCHECK(IsValid()); 145 ++iterator_; 146} 147 148void LevelDBTransaction::DataIterator::Prev() { 149 DCHECK(IsValid()); 150 if (iterator_ != data_->begin()) 151 --iterator_; 152 else 153 iterator_ = data_->end(); 154} 155 156StringPiece LevelDBTransaction::DataIterator::Key() const { 157 DCHECK(IsValid()); 158 return iterator_->first; 159} 160 161StringPiece LevelDBTransaction::DataIterator::Value() const { 162 DCHECK(IsValid()); 163 DCHECK(!IsDeleted()); 164 return iterator_->second->value; 165} 166 167bool LevelDBTransaction::DataIterator::IsDeleted() const { 168 DCHECK(IsValid()); 169 return iterator_->second->deleted; 170} 171 172LevelDBTransaction::DataIterator::~DataIterator() {} 173 174LevelDBTransaction::DataIterator::DataIterator(LevelDBTransaction* transaction) 175 : data_(&transaction->data_), 176 iterator_(data_->end()) {} 177 178scoped_ptr<LevelDBTransaction::TransactionIterator> 179LevelDBTransaction::TransactionIterator::Create( 180 scoped_refptr<LevelDBTransaction> transaction) { 181 return make_scoped_ptr(new TransactionIterator(transaction)); 182} 183 184LevelDBTransaction::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); 194} 195 196LevelDBTransaction::TransactionIterator::~TransactionIterator() { 197 transaction_->UnregisterIterator(this); 198} 199 200bool LevelDBTransaction::TransactionIterator::IsValid() const { 201 return !!current_; 202} 203 204void LevelDBTransaction::TransactionIterator::SeekToLast() { 205 data_iterator_->SeekToLast(); 206 db_iterator_->SeekToLast(); 207 direction_ = REVERSE; 208 209 HandleConflictsAndDeletes(); 210 SetCurrentIteratorToLargestKey(); 211} 212 213void LevelDBTransaction::TransactionIterator::Seek(const StringPiece& target) { 214 data_iterator_->Seek(target); 215 db_iterator_->Seek(target); 216 direction_ = FORWARD; 217 218 HandleConflictsAndDeletes(); 219 SetCurrentIteratorToSmallestKey(); 220} 221 222void LevelDBTransaction::TransactionIterator::Next() { 223 DCHECK(IsValid()); 224 if (data_changed_) 225 RefreshDataIterator(); 226 227 if (direction_ != FORWARD) { 228 // Ensure the non-current iterator is positioned after Key(). 229 230 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 231 ? data_iterator_.get() 232 : db_iterator_.get(); 233 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(); 240 } 241 DCHECK(!non_current->IsValid() || 242 comparator_->Compare(non_current->Key(), Key()) > 0); 243 244 direction_ = FORWARD; 245 } 246 247 current_->Next(); 248 HandleConflictsAndDeletes(); 249 SetCurrentIteratorToSmallestKey(); 250} 251 252void LevelDBTransaction::TransactionIterator::Prev() { 253 DCHECK(IsValid()); 254 if (data_changed_) 255 RefreshDataIterator(); 256 257 if (direction_ != REVERSE) { 258 // Ensure the non-current iterator is positioned before Key(). 259 260 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 261 ? data_iterator_.get() 262 : db_iterator_.get(); 263 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(); 274 } 275 DCHECK(!non_current->IsValid() || 276 comparator_->Compare(non_current->Key(), Key()) < 0); 277 278 direction_ = REVERSE; 279 } 280 281 current_->Prev(); 282 HandleConflictsAndDeletes(); 283 SetCurrentIteratorToLargestKey(); 284} 285 286StringPiece LevelDBTransaction::TransactionIterator::Key() const { 287 DCHECK(IsValid()); 288 if (data_changed_) 289 RefreshDataIterator(); 290 return current_->Key(); 291} 292 293StringPiece LevelDBTransaction::TransactionIterator::Value() const { 294 DCHECK(IsValid()); 295 if (data_changed_) 296 RefreshDataIterator(); 297 return current_->Value(); 298} 299 300void LevelDBTransaction::TransactionIterator::DataChanged() { 301 data_changed_ = true; 302} 303 304void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const { 305 DCHECK(data_changed_); 306 307 data_changed_ = false; 308 309 if (data_iterator_->IsValid() && data_iterator_.get() == current_) { 310 return; 311 } 312 313 if (db_iterator_->IsValid()) { 314 // There could be new records in data that we should iterate over. 315 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(); 323 } 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(); 330 } 331 } 332} 333 334bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const { 335 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0; 336} 337 338bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const { 339 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0; 340} 341 342void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { 343 bool loop = true; 344 345 while (loop) { 346 loop = false; 347 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(); 356 } 357 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; 369 } 370 } 371 } 372} 373 374void 375LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() { 376 LevelDBIterator* smallest = 0; 377 378 if (data_iterator_->IsValid()) 379 smallest = data_iterator_.get(); 380 381 if (db_iterator_->IsValid()) { 382 if (!smallest || 383 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0) 384 smallest = db_iterator_.get(); 385 } 386 387 current_ = smallest; 388} 389 390void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() { 391 LevelDBIterator* largest = 0; 392 393 if (data_iterator_->IsValid()) 394 largest = data_iterator_.get(); 395 396 if (db_iterator_->IsValid()) { 397 if (!largest || 398 comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0) 399 largest = db_iterator_.get(); 400 } 401 402 current_ = largest; 403} 404 405void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) { 406 DCHECK(iterators_.find(iterator) == iterators_.end()); 407 iterators_.insert(iterator); 408} 409 410void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) { 411 DCHECK(iterators_.find(iterator) != iterators_.end()); 412 iterators_.erase(iterator); 413} 414 415void 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(); 421 } 422} 423 424scoped_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create( 425 LevelDBDatabase* db) { 426 return make_scoped_ptr(new LevelDBDirectTransaction(db)); 427} 428 429LevelDBDirectTransaction::LevelDBDirectTransaction(LevelDBDatabase* db) 430 : db_(db), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {} 431 432LevelDBDirectTransaction::~LevelDBDirectTransaction() { 433 write_batch_->Clear(); 434} 435 436void LevelDBDirectTransaction::Put(const StringPiece& key, 437 const std::string* value) { 438 DCHECK(!finished_); 439 write_batch_->Put(key, *value); 440} 441 442leveldb::Status LevelDBDirectTransaction::Get(const StringPiece& key, 443 std::string* value, 444 bool* found) { 445 *found = false; 446 DCHECK(!finished_); 447 448 leveldb::Status s = db_->Get(key, value, found); 449 DCHECK(s.ok() || !*found); 450 return s; 451} 452 453void LevelDBDirectTransaction::Remove(const StringPiece& key) { 454 DCHECK(!finished_); 455 write_batch_->Remove(key); 456} 457 458leveldb::Status LevelDBDirectTransaction::Commit() { 459 DCHECK(!finished_); 460 461 leveldb::Status s = db_->Write(*write_batch_); 462 if (s.ok()) { 463 finished_ = true; 464 write_batch_->Clear(); 465 } 466 return s; 467} 468 469} // namespace content 470