leveldb_transaction.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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 133leveldb::Status LevelDBTransaction::DataIterator::SeekToLast() { 134 iterator_ = data_->end(); 135 if (iterator_ != data_->begin()) 136 --iterator_; 137 return leveldb::Status::OK(); 138} 139 140leveldb::Status LevelDBTransaction::DataIterator::Seek( 141 const StringPiece& target) { 142 iterator_ = data_->lower_bound(target); 143 return leveldb::Status::OK(); 144} 145 146leveldb::Status LevelDBTransaction::DataIterator::Next() { 147 DCHECK(IsValid()); 148 ++iterator_; 149 return leveldb::Status::OK(); 150} 151 152leveldb::Status LevelDBTransaction::DataIterator::Prev() { 153 DCHECK(IsValid()); 154 if (iterator_ != data_->begin()) 155 --iterator_; 156 else 157 iterator_ = data_->end(); 158 return leveldb::Status::OK(); 159} 160 161StringPiece LevelDBTransaction::DataIterator::Key() const { 162 DCHECK(IsValid()); 163 return iterator_->first; 164} 165 166StringPiece LevelDBTransaction::DataIterator::Value() const { 167 DCHECK(IsValid()); 168 DCHECK(!IsDeleted()); 169 return iterator_->second->value; 170} 171 172bool LevelDBTransaction::DataIterator::IsDeleted() const { 173 DCHECK(IsValid()); 174 return iterator_->second->deleted; 175} 176 177LevelDBTransaction::DataIterator::~DataIterator() {} 178 179LevelDBTransaction::DataIterator::DataIterator(LevelDBTransaction* transaction) 180 : data_(&transaction->data_), 181 iterator_(data_->end()) {} 182 183scoped_ptr<LevelDBTransaction::TransactionIterator> 184LevelDBTransaction::TransactionIterator::Create( 185 scoped_refptr<LevelDBTransaction> transaction) { 186 return make_scoped_ptr(new TransactionIterator(transaction)); 187} 188 189LevelDBTransaction::TransactionIterator::TransactionIterator( 190 scoped_refptr<LevelDBTransaction> transaction) 191 : transaction_(transaction), 192 comparator_(transaction_->comparator_), 193 data_iterator_(DataIterator::Create(transaction_.get())), 194 db_iterator_(transaction_->db_->CreateIterator(&transaction_->snapshot_)), 195 current_(0), 196 direction_(FORWARD), 197 data_changed_(false) { 198 transaction_->RegisterIterator(this); 199} 200 201LevelDBTransaction::TransactionIterator::~TransactionIterator() { 202 transaction_->UnregisterIterator(this); 203} 204 205bool LevelDBTransaction::TransactionIterator::IsValid() const { 206 return !!current_; 207} 208 209leveldb::Status LevelDBTransaction::TransactionIterator::SeekToLast() { 210 leveldb::Status s = data_iterator_->SeekToLast(); 211 DCHECK(s.ok()); 212 s = db_iterator_->SeekToLast(); 213 if (!s.ok()) 214 return s; 215 direction_ = REVERSE; 216 217 HandleConflictsAndDeletes(); 218 SetCurrentIteratorToLargestKey(); 219 return s; 220} 221 222leveldb::Status LevelDBTransaction::TransactionIterator::Seek( 223 const StringPiece& target) { 224 leveldb::Status s = data_iterator_->Seek(target); 225 DCHECK(s.ok()); 226 s = db_iterator_->Seek(target); 227 if (!s.ok()) 228 return s; 229 direction_ = FORWARD; 230 231 HandleConflictsAndDeletes(); 232 SetCurrentIteratorToSmallestKey(); 233 return s; 234} 235 236leveldb::Status LevelDBTransaction::TransactionIterator::Next() { 237 DCHECK(IsValid()); 238 if (data_changed_) 239 RefreshDataIterator(); 240 241 leveldb::Status s; 242 if (direction_ != FORWARD) { 243 // Ensure the non-current iterator is positioned after Key(). 244 245 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 246 ? data_iterator_.get() 247 : db_iterator_.get(); 248 249 non_current->Seek(Key()); 250 if (non_current->IsValid() && 251 !comparator_->Compare(non_current->Key(), Key())) { 252 // Take an extra step so the non-current key is 253 // strictly greater than Key(). 254 s = non_current->Next(); 255 if (!s.ok()) 256 return s; 257 } 258 DCHECK(!non_current->IsValid() || 259 comparator_->Compare(non_current->Key(), Key()) > 0); 260 261 direction_ = FORWARD; 262 } 263 264 s = current_->Next(); 265 if (!s.ok()) 266 return s; 267 HandleConflictsAndDeletes(); 268 SetCurrentIteratorToSmallestKey(); 269 return leveldb::Status::OK(); 270} 271 272leveldb::Status LevelDBTransaction::TransactionIterator::Prev() { 273 DCHECK(IsValid()); 274 leveldb::Status s; 275 if (data_changed_) 276 RefreshDataIterator(); 277 278 if (direction_ != REVERSE) { 279 // Ensure the non-current iterator is positioned before Key(). 280 281 LevelDBIterator* non_current = (current_ == db_iterator_.get()) 282 ? data_iterator_.get() 283 : db_iterator_.get(); 284 285 s = non_current->Seek(Key()); 286 if (!s.ok()) 287 return s; 288 if (non_current->IsValid()) { 289 // Iterator is at first entry >= Key(). 290 // Step back once to entry < key. 291 // This is why we don't check for the keys being the same before 292 // stepping, like we do in Next() above. 293 non_current->Prev(); 294 } else { 295 // Iterator has no entries >= Key(). Position at last entry. 296 non_current->SeekToLast(); 297 } 298 DCHECK(!non_current->IsValid() || 299 comparator_->Compare(non_current->Key(), Key()) < 0); 300 301 direction_ = REVERSE; 302 } 303 304 s = current_->Prev(); 305 if (!s.ok()) 306 return s; 307 HandleConflictsAndDeletes(); 308 SetCurrentIteratorToLargestKey(); 309 return leveldb::Status::OK(); 310} 311 312StringPiece LevelDBTransaction::TransactionIterator::Key() const { 313 DCHECK(IsValid()); 314 if (data_changed_) 315 RefreshDataIterator(); 316 return current_->Key(); 317} 318 319StringPiece LevelDBTransaction::TransactionIterator::Value() const { 320 DCHECK(IsValid()); 321 if (data_changed_) 322 RefreshDataIterator(); 323 return current_->Value(); 324} 325 326void LevelDBTransaction::TransactionIterator::DataChanged() { 327 data_changed_ = true; 328} 329 330void LevelDBTransaction::TransactionIterator::RefreshDataIterator() const { 331 DCHECK(data_changed_); 332 333 data_changed_ = false; 334 335 if (data_iterator_->IsValid() && data_iterator_.get() == current_) { 336 return; 337 } 338 339 if (db_iterator_->IsValid()) { 340 // There could be new records in data that we should iterate over. 341 342 if (direction_ == FORWARD) { 343 // Try to seek data iterator to something greater than the db iterator. 344 data_iterator_->Seek(db_iterator_->Key()); 345 if (data_iterator_->IsValid() && 346 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) { 347 // If equal, take another step so the data iterator is strictly greater. 348 data_iterator_->Next(); 349 } 350 } else { 351 // If going backward, seek to a key less than the db iterator. 352 DCHECK_EQ(REVERSE, direction_); 353 data_iterator_->Seek(db_iterator_->Key()); 354 if (data_iterator_->IsValid()) 355 data_iterator_->Prev(); 356 } 357 } 358} 359 360bool LevelDBTransaction::TransactionIterator::DataIteratorIsLower() const { 361 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) < 0; 362} 363 364bool LevelDBTransaction::TransactionIterator::DataIteratorIsHigher() const { 365 return comparator_->Compare(data_iterator_->Key(), db_iterator_->Key()) > 0; 366} 367 368void LevelDBTransaction::TransactionIterator::HandleConflictsAndDeletes() { 369 bool loop = true; 370 371 while (loop) { 372 loop = false; 373 374 if (data_iterator_->IsValid() && db_iterator_->IsValid() && 375 !comparator_->Compare(data_iterator_->Key(), db_iterator_->Key())) { 376 // For equal keys, the data iterator takes precedence, so move the 377 // database iterator another step. 378 if (direction_ == FORWARD) 379 db_iterator_->Next(); 380 else 381 db_iterator_->Prev(); 382 } 383 384 // Skip over delete markers in the data iterator until it catches up with 385 // the db iterator. 386 if (data_iterator_->IsValid() && data_iterator_->IsDeleted()) { 387 if (direction_ == FORWARD && 388 (!db_iterator_->IsValid() || DataIteratorIsLower())) { 389 data_iterator_->Next(); 390 loop = true; 391 } else if (direction_ == REVERSE && 392 (!db_iterator_->IsValid() || DataIteratorIsHigher())) { 393 data_iterator_->Prev(); 394 loop = true; 395 } 396 } 397 } 398} 399 400void 401LevelDBTransaction::TransactionIterator::SetCurrentIteratorToSmallestKey() { 402 LevelDBIterator* smallest = 0; 403 404 if (data_iterator_->IsValid()) 405 smallest = data_iterator_.get(); 406 407 if (db_iterator_->IsValid()) { 408 if (!smallest || 409 comparator_->Compare(db_iterator_->Key(), smallest->Key()) < 0) 410 smallest = db_iterator_.get(); 411 } 412 413 current_ = smallest; 414} 415 416void LevelDBTransaction::TransactionIterator::SetCurrentIteratorToLargestKey() { 417 LevelDBIterator* largest = 0; 418 419 if (data_iterator_->IsValid()) 420 largest = data_iterator_.get(); 421 422 if (db_iterator_->IsValid()) { 423 if (!largest || 424 comparator_->Compare(db_iterator_->Key(), largest->Key()) > 0) 425 largest = db_iterator_.get(); 426 } 427 428 current_ = largest; 429} 430 431void LevelDBTransaction::RegisterIterator(TransactionIterator* iterator) { 432 DCHECK(iterators_.find(iterator) == iterators_.end()); 433 iterators_.insert(iterator); 434} 435 436void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) { 437 DCHECK(iterators_.find(iterator) != iterators_.end()); 438 iterators_.erase(iterator); 439} 440 441void LevelDBTransaction::NotifyIterators() { 442 for (std::set<TransactionIterator*>::iterator i = iterators_.begin(); 443 i != iterators_.end(); 444 ++i) { 445 TransactionIterator* transaction_iterator = *i; 446 transaction_iterator->DataChanged(); 447 } 448} 449 450scoped_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create( 451 LevelDBDatabase* db) { 452 return make_scoped_ptr(new LevelDBDirectTransaction(db)); 453} 454 455LevelDBDirectTransaction::LevelDBDirectTransaction(LevelDBDatabase* db) 456 : db_(db), write_batch_(LevelDBWriteBatch::Create()), finished_(false) {} 457 458LevelDBDirectTransaction::~LevelDBDirectTransaction() { 459 write_batch_->Clear(); 460} 461 462void LevelDBDirectTransaction::Put(const StringPiece& key, 463 const std::string* value) { 464 DCHECK(!finished_); 465 write_batch_->Put(key, *value); 466} 467 468leveldb::Status LevelDBDirectTransaction::Get(const StringPiece& key, 469 std::string* value, 470 bool* found) { 471 *found = false; 472 DCHECK(!finished_); 473 474 leveldb::Status s = db_->Get(key, value, found); 475 DCHECK(s.ok() || !*found); 476 return s; 477} 478 479void LevelDBDirectTransaction::Remove(const StringPiece& key) { 480 DCHECK(!finished_); 481 write_batch_->Remove(key); 482} 483 484leveldb::Status LevelDBDirectTransaction::Commit() { 485 DCHECK(!finished_); 486 487 leveldb::Status s = db_->Write(*write_batch_); 488 if (s.ok()) { 489 finished_ = true; 490 write_batch_->Clear(); 491 } 492 return s; 493} 494 495} // namespace content 496