leveldb_database.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_database.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cerrno> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file.h" 11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string16.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_piece.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/stringprintf.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_info.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_iterator.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_write_batch.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/env_chromium.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/env_idb.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/env.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/slice.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::StringPiece; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 322385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Forcing flushes to disk at the end of a transaction guarantees that the 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data hit disk, but drastically impacts throughput when the filesystem is 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// busy with background compactions. Not syncing trades off reliability for 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// performance. Note that background compactions which move data from the 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// log to SSTs are always done with reliable writes. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sync writes are necessary on Windows for quota calculations; POSIX 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// calculates file sizes correctly even when not synced to disk. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const bool kSyncWrites = true; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dgrogan): Either remove the #if block or change this back to false. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See http://crbug.com/338385. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const bool kSyncWrites = true; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static leveldb::Slice MakeSlice(const StringPiece& s) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return leveldb::Slice(s.begin(), s.size()); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static StringPiece MakeStringPiece(const leveldb::Slice& s) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StringPiece(s.data(), s.size()); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LevelDBDatabase::ComparatorAdapter::ComparatorAdapter( 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LevelDBComparator* comparator) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : comparator_(comparator) {} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int LevelDBDatabase::ComparatorAdapter::Compare(const leveldb::Slice& a, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const leveldb::Slice& b) const { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return comparator_->Compare(MakeStringPiece(a), MakeStringPiece(b)); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* LevelDBDatabase::ComparatorAdapter::Name() const { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return comparator_->Name(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jsbell): Support the methods below in the future. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LevelDBDatabase::ComparatorAdapter::FindShortestSeparator( 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* start, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const leveldb::Slice& limit) const {} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LevelDBDatabase::ComparatorAdapter::FindShortSuccessor( 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* key) const {} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LevelDBDatabase::LevelDBDatabase() {} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LevelDBDatabase::~LevelDBDatabase() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // db_'s destructor uses comparator_adapter_; order of deletion is important. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) db_.reset(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) comparator_adapter_.reset(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) env_.reset(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static leveldb::Status OpenDB(leveldb::Comparator* comparator, 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) leveldb::Env* env, 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::FilePath& path, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::DB** db) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leveldb::Options options; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options.comparator = comparator; 98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) options.create_if_missing = true; 99 options.paranoid_checks = true; 100 options.compression = leveldb::kSnappyCompression; 101 102 // For info about the troubles we've run into with this parameter, see: 103 // https://code.google.com/p/chromium/issues/detail?id=227313#c11 104 options.max_open_files = 80; 105 options.env = env; 106 107 // ChromiumEnv assumes UTF8, converts back to FilePath before using. 108 return leveldb::DB::Open(options, path.AsUTF8Unsafe(), db); 109} 110 111leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) { 112 leveldb::Options options; 113 options.env = leveldb::IDBEnv(); 114 // ChromiumEnv assumes UTF8, converts back to FilePath before using. 115 return leveldb::DestroyDB(file_name.AsUTF8Unsafe(), options); 116} 117 118namespace { 119class LockImpl : public LevelDBLock { 120 public: 121 explicit LockImpl(leveldb::Env* env, leveldb::FileLock* lock) 122 : env_(env), lock_(lock) {} 123 virtual ~LockImpl() { env_->UnlockFile(lock_); } 124 private: 125 leveldb::Env* env_; 126 leveldb::FileLock* lock_; 127}; 128} 129 130scoped_ptr<LevelDBLock> LevelDBDatabase::LockForTesting( 131 const base::FilePath& file_name) { 132 leveldb::Env* env = leveldb::IDBEnv(); 133 base::FilePath lock_path = file_name.AppendASCII("LOCK"); 134 leveldb::FileLock* lock = NULL; 135 leveldb::Status status = env->LockFile(lock_path.AsUTF8Unsafe(), &lock); 136 if (!status.ok()) 137 return scoped_ptr<LevelDBLock>(); 138 DCHECK(lock); 139 return scoped_ptr<LevelDBLock>(new LockImpl(env, lock)); 140} 141 142static int CheckFreeSpace(const char* const type, 143 const base::FilePath& file_name) { 144 std::string name = 145 std::string("WebCore.IndexedDB.LevelDB.Open") + type + "FreeDiskSpace"; 146 int64 free_disk_space_in_k_bytes = 147 base::SysInfo::AmountOfFreeDiskSpace(file_name) / 1024; 148 if (free_disk_space_in_k_bytes < 0) { 149 base::Histogram::FactoryGet( 150 "WebCore.IndexedDB.LevelDB.FreeDiskSpaceFailure", 151 1, 152 2 /*boundary*/, 153 2 /*boundary*/ + 1, 154 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(1 /*sample*/); 155 return -1; 156 } 157 int clamped_disk_space_k_bytes = free_disk_space_in_k_bytes > INT_MAX 158 ? INT_MAX 159 : free_disk_space_in_k_bytes; 160 const uint64 histogram_max = static_cast<uint64>(1e9); 161 COMPILE_ASSERT(histogram_max <= INT_MAX, histogram_max_too_big); 162 base::Histogram::FactoryGet(name, 163 1, 164 histogram_max, 165 11 /*buckets*/, 166 base::HistogramBase::kUmaTargetedHistogramFlag) 167 ->Add(clamped_disk_space_k_bytes); 168 return clamped_disk_space_k_bytes; 169} 170 171static void ParseAndHistogramIOErrorDetails(const std::string& histogram_name, 172 const leveldb::Status& s) { 173 leveldb_env::MethodID method; 174 int error = -1; 175 leveldb_env::ErrorParsingResult result = 176 leveldb_env::ParseMethodAndError(s.ToString().c_str(), &method, &error); 177 if (result == leveldb_env::NONE) 178 return; 179 std::string method_histogram_name(histogram_name); 180 method_histogram_name.append(".EnvMethod"); 181 base::LinearHistogram::FactoryGet( 182 method_histogram_name, 183 1, 184 leveldb_env::kNumEntries, 185 leveldb_env::kNumEntries + 1, 186 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(method); 187 188 std::string error_histogram_name(histogram_name); 189 190 if (result == leveldb_env::METHOD_AND_PFE) { 191 DCHECK(error < 0); 192 error_histogram_name.append(std::string(".PFE.") + 193 leveldb_env::MethodIDToString(method)); 194 base::LinearHistogram::FactoryGet( 195 error_histogram_name, 196 1, 197 -base::File::FILE_ERROR_MAX, 198 -base::File::FILE_ERROR_MAX + 1, 199 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(-error); 200 } else if (result == leveldb_env::METHOD_AND_ERRNO) { 201 error_histogram_name.append(std::string(".Errno.") + 202 leveldb_env::MethodIDToString(method)); 203 base::LinearHistogram::FactoryGet( 204 error_histogram_name, 205 1, 206 ERANGE + 1, 207 ERANGE + 2, 208 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error); 209 } 210} 211 212static void ParseAndHistogramCorruptionDetails( 213 const std::string& histogram_name, 214 const leveldb::Status& status) { 215 int error = leveldb_env::GetCorruptionCode(status); 216 DCHECK(error >= 0); 217 std::string corruption_histogram_name(histogram_name); 218 corruption_histogram_name.append(".Corruption"); 219 const int kNumPatterns = leveldb_env::GetNumCorruptionCodes(); 220 base::LinearHistogram::FactoryGet( 221 corruption_histogram_name, 222 1, 223 kNumPatterns, 224 kNumPatterns + 1, 225 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error); 226} 227 228static void HistogramLevelDBError(const std::string& histogram_name, 229 const leveldb::Status& s) { 230 if (s.ok()) { 231 NOTREACHED(); 232 return; 233 } 234 enum { 235 LEVEL_DB_NOT_FOUND, 236 LEVEL_DB_CORRUPTION, 237 LEVEL_DB_IO_ERROR, 238 LEVEL_DB_OTHER, 239 LEVEL_DB_MAX_ERROR 240 }; 241 int leveldb_error = LEVEL_DB_OTHER; 242 if (s.IsNotFound()) 243 leveldb_error = LEVEL_DB_NOT_FOUND; 244 else if (s.IsCorruption()) 245 leveldb_error = LEVEL_DB_CORRUPTION; 246 else if (s.IsIOError()) 247 leveldb_error = LEVEL_DB_IO_ERROR; 248 base::Histogram::FactoryGet(histogram_name, 249 1, 250 LEVEL_DB_MAX_ERROR, 251 LEVEL_DB_MAX_ERROR + 1, 252 base::HistogramBase::kUmaTargetedHistogramFlag) 253 ->Add(leveldb_error); 254 if (s.IsIOError()) 255 ParseAndHistogramIOErrorDetails(histogram_name, s); 256 else 257 ParseAndHistogramCorruptionDetails(histogram_name, s); 258} 259 260leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, 261 const LevelDBComparator* comparator, 262 scoped_ptr<LevelDBDatabase>* result, 263 bool* is_disk_full) { 264 scoped_ptr<ComparatorAdapter> comparator_adapter( 265 new ComparatorAdapter(comparator)); 266 267 leveldb::DB* db; 268 const leveldb::Status s = 269 OpenDB(comparator_adapter.get(), leveldb::IDBEnv(), file_name, &db); 270 271 if (!s.ok()) { 272 HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s); 273 int free_space_k_bytes = CheckFreeSpace("Failure", file_name); 274 // Disks with <100k of free space almost never succeed in opening a 275 // leveldb database. 276 if (is_disk_full) 277 *is_disk_full = free_space_k_bytes >= 0 && free_space_k_bytes < 100; 278 279 LOG(ERROR) << "Failed to open LevelDB database from " 280 << file_name.AsUTF8Unsafe() << "," << s.ToString(); 281 return s; 282 } 283 284 CheckFreeSpace("Success", file_name); 285 286 (*result).reset(new LevelDBDatabase); 287 (*result)->db_ = make_scoped_ptr(db); 288 (*result)->comparator_adapter_ = comparator_adapter.Pass(); 289 (*result)->comparator_ = comparator; 290 291 return s; 292} 293 294scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory( 295 const LevelDBComparator* comparator) { 296 scoped_ptr<ComparatorAdapter> comparator_adapter( 297 new ComparatorAdapter(comparator)); 298 scoped_ptr<leveldb::Env> in_memory_env(leveldb::NewMemEnv(leveldb::IDBEnv())); 299 300 leveldb::DB* db; 301 const leveldb::Status s = OpenDB( 302 comparator_adapter.get(), in_memory_env.get(), base::FilePath(), &db); 303 304 if (!s.ok()) { 305 LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString(); 306 return scoped_ptr<LevelDBDatabase>(); 307 } 308 309 scoped_ptr<LevelDBDatabase> result(new LevelDBDatabase); 310 result->env_ = in_memory_env.Pass(); 311 result->db_ = make_scoped_ptr(db); 312 result->comparator_adapter_ = comparator_adapter.Pass(); 313 result->comparator_ = comparator; 314 315 return result.Pass(); 316} 317 318leveldb::Status LevelDBDatabase::Put(const StringPiece& key, 319 std::string* value) { 320 leveldb::WriteOptions write_options; 321 write_options.sync = kSyncWrites; 322 323 const leveldb::Status s = 324 db_->Put(write_options, MakeSlice(key), MakeSlice(*value)); 325 if (!s.ok()) 326 LOG(ERROR) << "LevelDB put failed: " << s.ToString(); 327 return s; 328} 329 330leveldb::Status LevelDBDatabase::Remove(const StringPiece& key) { 331 leveldb::WriteOptions write_options; 332 write_options.sync = kSyncWrites; 333 334 const leveldb::Status s = db_->Delete(write_options, MakeSlice(key)); 335 if (!s.IsNotFound()) 336 LOG(ERROR) << "LevelDB remove failed: " << s.ToString(); 337 return s; 338} 339 340leveldb::Status LevelDBDatabase::Get(const StringPiece& key, 341 std::string* value, 342 bool* found, 343 const LevelDBSnapshot* snapshot) { 344 *found = false; 345 leveldb::ReadOptions read_options; 346 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the 347 // performance impact is too great. 348 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0; 349 350 const leveldb::Status s = db_->Get(read_options, MakeSlice(key), value); 351 if (s.ok()) { 352 *found = true; 353 return s; 354 } 355 if (s.IsNotFound()) 356 return leveldb::Status::OK(); 357 HistogramLevelDBError("WebCore.IndexedDB.LevelDBReadErrors", s); 358 LOG(ERROR) << "LevelDB get failed: " << s.ToString(); 359 return s; 360} 361 362leveldb::Status LevelDBDatabase::Write(const LevelDBWriteBatch& write_batch) { 363 leveldb::WriteOptions write_options; 364 write_options.sync = kSyncWrites; 365 366 const leveldb::Status s = 367 db_->Write(write_options, write_batch.write_batch_.get()); 368 if (!s.ok()) { 369 HistogramLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s); 370 LOG(ERROR) << "LevelDB write failed: " << s.ToString(); 371 } 372 return s; 373} 374 375namespace { 376class IteratorImpl : public LevelDBIterator { 377 public: 378 virtual ~IteratorImpl() {} 379 380 virtual bool IsValid() const OVERRIDE; 381 virtual leveldb::Status SeekToLast() OVERRIDE; 382 virtual leveldb::Status Seek(const StringPiece& target) OVERRIDE; 383 virtual leveldb::Status Next() OVERRIDE; 384 virtual leveldb::Status Prev() OVERRIDE; 385 virtual StringPiece Key() const OVERRIDE; 386 virtual StringPiece Value() const OVERRIDE; 387 388 private: 389 friend class content::LevelDBDatabase; 390 explicit IteratorImpl(scoped_ptr<leveldb::Iterator> iterator); 391 void CheckStatus(); 392 393 scoped_ptr<leveldb::Iterator> iterator_; 394}; 395} 396 397IteratorImpl::IteratorImpl(scoped_ptr<leveldb::Iterator> it) 398 : iterator_(it.Pass()) {} 399 400void IteratorImpl::CheckStatus() { 401 const leveldb::Status& s = iterator_->status(); 402 if (!s.ok()) 403 LOG(ERROR) << "LevelDB iterator error: " << s.ToString(); 404} 405 406bool IteratorImpl::IsValid() const { return iterator_->Valid(); } 407 408leveldb::Status IteratorImpl::SeekToLast() { 409 iterator_->SeekToLast(); 410 CheckStatus(); 411 return iterator_->status(); 412} 413 414leveldb::Status IteratorImpl::Seek(const StringPiece& target) { 415 iterator_->Seek(MakeSlice(target)); 416 CheckStatus(); 417 return iterator_->status(); 418} 419 420leveldb::Status IteratorImpl::Next() { 421 DCHECK(IsValid()); 422 iterator_->Next(); 423 CheckStatus(); 424 return iterator_->status(); 425} 426 427leveldb::Status IteratorImpl::Prev() { 428 DCHECK(IsValid()); 429 iterator_->Prev(); 430 CheckStatus(); 431 return iterator_->status(); 432} 433 434StringPiece IteratorImpl::Key() const { 435 DCHECK(IsValid()); 436 return MakeStringPiece(iterator_->key()); 437} 438 439StringPiece IteratorImpl::Value() const { 440 DCHECK(IsValid()); 441 return MakeStringPiece(iterator_->value()); 442} 443 444scoped_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator( 445 const LevelDBSnapshot* snapshot) { 446 leveldb::ReadOptions read_options; 447 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the 448 // performance impact is too great. 449 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0; 450 451 scoped_ptr<leveldb::Iterator> i(db_->NewIterator(read_options)); 452 return scoped_ptr<LevelDBIterator>(new IteratorImpl(i.Pass())); 453} 454 455const LevelDBComparator* LevelDBDatabase::Comparator() const { 456 return comparator_; 457} 458 459void LevelDBDatabase::Compact(const base::StringPiece& start, 460 const base::StringPiece& stop) { 461 const leveldb::Slice start_slice = MakeSlice(start); 462 const leveldb::Slice stop_slice = MakeSlice(stop); 463 db_->CompactRange(&start_slice, &stop_slice); 464} 465 466void LevelDBDatabase::CompactAll() { db_->CompactRange(NULL, NULL); } 467 468} // namespace content 469