1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_database.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <cerrno>
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/basictypes.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/file.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/metrics/histogram.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/strings/string_piece.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/stringprintf.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/sys_info.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/indexed_db/indexed_db_class_factory.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/leveldatabase/env_chromium.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/env_idb.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/db.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/env.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h"
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/leveldatabase/src/include/leveldb/slice.h"
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochusing base::StringPiece;
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace content {
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Forcing flushes to disk at the end of a transaction guarantees that the
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// data hit disk, but drastically impacts throughput when the filesystem is
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// busy with background compactions. Not syncing trades off reliability for
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// performance. Note that background compactions which move data from the
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// log to SSTs are always done with reliable writes.
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)//
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Sync writes are necessary on Windows for quota calculations; POSIX
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// calculates file sizes correctly even when not synced to disk.
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_WIN)
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static const bool kSyncWrites = true;
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#else
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(dgrogan): Either remove the #if block or change this back to false.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// See http://crbug.com/338385.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static const bool kSyncWrites = true;
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic leveldb::Slice MakeSlice(const StringPiece& s) {
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return leveldb::Slice(s.begin(), s.size());
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic StringPiece MakeStringPiece(const leveldb::Slice& s) {
567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return StringPiece(s.data(), s.size());
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
59effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochLevelDBDatabase::ComparatorAdapter::ComparatorAdapter(
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const LevelDBComparator* comparator)
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : comparator_(comparator) {}
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochint LevelDBDatabase::ComparatorAdapter::Compare(const leveldb::Slice& a,
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                                const leveldb::Slice& b) const {
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return comparator_->Compare(MakeStringPiece(a), MakeStringPiece(b));
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char* LevelDBDatabase::ComparatorAdapter::Name() const {
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return comparator_->Name();
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// TODO(jsbell): Support the methods below in the future.
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LevelDBDatabase::ComparatorAdapter::FindShortestSeparator(
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string* start,
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const leveldb::Slice& limit) const {}
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LevelDBDatabase::ComparatorAdapter::FindShortSuccessor(
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string* key) const {}
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db)
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {}
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); }
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)LevelDBDatabase::LevelDBDatabase() {}
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)LevelDBDatabase::~LevelDBDatabase() {
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // db_'s destructor uses comparator_adapter_; order of deletion is important.
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  db_.reset();
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  comparator_adapter_.reset();
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  env_.reset();
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic leveldb::Status OpenDB(
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    leveldb::Comparator* comparator,
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    leveldb::Env* env,
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::FilePath& path,
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    leveldb::DB** db,
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<const leveldb::FilterPolicy>* filter_policy) {
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  filter_policy->reset(leveldb::NewBloomFilterPolicy(10));
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::Options options;
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.comparator = comparator;
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.create_if_missing = true;
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.paranoid_checks = true;
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  options.filter_policy = filter_policy->get();
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  options.compression = leveldb::kSnappyCompression;
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // For info about the troubles we've run into with this parameter, see:
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // https://code.google.com/p/chromium/issues/detail?id=227313#c11
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.max_open_files = 80;
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.env = env;
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // ChromiumEnv assumes UTF8, converts back to FilePath before using.
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  leveldb::Status s = leveldb::DB::Open(options, path.AsUTF8Unsafe(), db);
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return s;
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) {
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::Options options;
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  options.env = leveldb::IDBEnv();
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // ChromiumEnv assumes UTF8, converts back to FilePath before using.
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return leveldb::DestroyDB(file_name.AsUTF8Unsafe(), options);
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class LockImpl : public LevelDBLock {
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  explicit LockImpl(leveldb::Env* env, leveldb::FileLock* lock)
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      : env_(env), lock_(lock) {}
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~LockImpl() { env_->UnlockFile(lock_); }
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  leveldb::Env* env_;
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  leveldb::FileLock* lock_;
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(LockImpl);
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)scoped_ptr<LevelDBLock> LevelDBDatabase::LockForTesting(
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const base::FilePath& file_name) {
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  leveldb::Env* env = leveldb::IDBEnv();
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::FilePath lock_path = file_name.AppendASCII("LOCK");
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  leveldb::FileLock* lock = NULL;
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  leveldb::Status status = env->LockFile(lock_path.AsUTF8Unsafe(), &lock);
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!status.ok())
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return scoped_ptr<LevelDBLock>();
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(lock);
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return scoped_ptr<LevelDBLock>(new LockImpl(env, lock));
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int CheckFreeSpace(const char* const type,
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const base::FilePath& file_name) {
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string name =
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string("WebCore.IndexedDB.LevelDB.Open") + type + "FreeDiskSpace";
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 free_disk_space_in_k_bytes =
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::SysInfo::AmountOfFreeDiskSpace(file_name) / 1024;
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (free_disk_space_in_k_bytes < 0) {
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::Histogram::FactoryGet(
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        "WebCore.IndexedDB.LevelDB.FreeDiskSpaceFailure",
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        1,
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        2 /*boundary*/,
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        2 /*boundary*/ + 1,
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        base::HistogramBase::kUmaTargetedHistogramFlag)->Add(1 /*sample*/);
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return -1;
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
167424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  int clamped_disk_space_k_bytes = free_disk_space_in_k_bytes > INT_MAX
168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                       ? INT_MAX
169424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                       : free_disk_space_in_k_bytes;
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const uint64 histogram_max = static_cast<uint64>(1e9);
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  COMPILE_ASSERT(histogram_max <= INT_MAX, histogram_max_too_big);
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Histogram::FactoryGet(name,
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              1,
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              histogram_max,
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              11 /*buckets*/,
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              base::HistogramBase::kUmaTargetedHistogramFlag)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ->Add(clamped_disk_space_k_bytes);
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return clamped_disk_space_k_bytes;
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void ParseAndHistogramIOErrorDetails(const std::string& histogram_name,
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            const leveldb::Status& s) {
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  leveldb_env::MethodID method;
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int error = -1;
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  leveldb_env::ErrorParsingResult result =
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb_env::ParseMethodAndError(s.ToString().c_str(), &method, &error);
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (result == leveldb_env::NONE)
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string method_histogram_name(histogram_name);
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  method_histogram_name.append(".EnvMethod");
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::LinearHistogram::FactoryGet(
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      method_histogram_name,
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      1,
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb_env::kNumEntries,
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      leveldb_env::kNumEntries + 1,
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::HistogramBase::kUmaTargetedHistogramFlag)->Add(method);
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string error_histogram_name(histogram_name);
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (result == leveldb_env::METHOD_AND_PFE) {
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_LT(error, 0);
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    error_histogram_name.append(std::string(".PFE.") +
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                leveldb_env::MethodIDToString(method));
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::LinearHistogram::FactoryGet(
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        error_histogram_name,
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        1,
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        -base::File::FILE_ERROR_MAX,
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        -base::File::FILE_ERROR_MAX + 1,
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::HistogramBase::kUmaTargetedHistogramFlag)->Add(-error);
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (result == leveldb_env::METHOD_AND_ERRNO) {
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    error_histogram_name.append(std::string(".Errno.") +
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                leveldb_env::MethodIDToString(method));
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::LinearHistogram::FactoryGet(
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        error_histogram_name,
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        1,
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        ERANGE + 1,
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        ERANGE + 2,
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error);
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void ParseAndHistogramCorruptionDetails(
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& histogram_name,
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const leveldb::Status& status) {
2250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int error = leveldb_env::GetCorruptionCode(status);
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_GE(error, 0);
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string corruption_histogram_name(histogram_name);
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  corruption_histogram_name.append(".Corruption");
2290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const int kNumPatterns = leveldb_env::GetNumCorruptionCodes();
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::LinearHistogram::FactoryGet(
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      corruption_histogram_name,
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      1,
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      kNumPatterns,
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kNumPatterns + 1,
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error);
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static void HistogramLevelDBError(const std::string& histogram_name,
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                  const leveldb::Status& s) {
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (s.ok()) {
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NOTREACHED();
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  enum {
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LEVEL_DB_NOT_FOUND,
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LEVEL_DB_CORRUPTION,
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LEVEL_DB_IO_ERROR,
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LEVEL_DB_OTHER,
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LEVEL_DB_MAX_ERROR
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  };
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int leveldb_error = LEVEL_DB_OTHER;
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (s.IsNotFound())
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    leveldb_error = LEVEL_DB_NOT_FOUND;
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  else if (s.IsCorruption())
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    leveldb_error = LEVEL_DB_CORRUPTION;
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  else if (s.IsIOError())
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    leveldb_error = LEVEL_DB_IO_ERROR;
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::Histogram::FactoryGet(histogram_name,
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              1,
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              LEVEL_DB_MAX_ERROR,
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              LEVEL_DB_MAX_ERROR + 1,
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              base::HistogramBase::kUmaTargetedHistogramFlag)
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ->Add(leveldb_error);
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (s.IsIOError())
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ParseAndHistogramIOErrorDetails(histogram_name, s);
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  else
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ParseAndHistogramCorruptionDetails(histogram_name, s);
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
270424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name,
271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                      const LevelDBComparator* comparator,
272424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                      scoped_ptr<LevelDBDatabase>* result,
273424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                      bool* is_disk_full) {
2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::TimeTicks begin_time = base::TimeTicks::Now();
2756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<ComparatorAdapter> comparator_adapter(
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new ComparatorAdapter(comparator));
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::DB* db;
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<const leveldb::FilterPolicy> filter_policy;
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const leveldb::Status s = OpenDB(comparator_adapter.get(),
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   leveldb::IDBEnv(),
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   file_name,
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   &db,
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   &filter_policy);
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!s.ok()) {
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s);
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int free_space_k_bytes = CheckFreeSpace("Failure", file_name);
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Disks with <100k of free space almost never succeed in opening a
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // leveldb database.
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (is_disk_full)
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      *is_disk_full = free_space_k_bytes >= 0 && free_space_k_bytes < 100;
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(ERROR) << "Failed to open LevelDB database from "
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               << file_name.AsUTF8Unsafe() << "," << s.ToString();
297ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return s;
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime",
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             base::TimeTicks::Now() - begin_time);
3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CheckFreeSpace("Success", file_name);
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
305ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  (*result).reset(new LevelDBDatabase);
306ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  (*result)->db_ = make_scoped_ptr(db);
307ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  (*result)->comparator_adapter_ = comparator_adapter.Pass();
308ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  (*result)->comparator_ = comparator;
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  (*result)->filter_policy_ = filter_policy.Pass();
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
311ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return s;
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const LevelDBComparator* comparator) {
316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<ComparatorAdapter> comparator_adapter(
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new ComparatorAdapter(comparator));
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<leveldb::Env> in_memory_env(leveldb::NewMemEnv(leveldb::IDBEnv()));
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::DB* db;
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<const leveldb::FilterPolicy> filter_policy;
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const leveldb::Status s = OpenDB(comparator_adapter.get(),
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   in_memory_env.get(),
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   base::FilePath(),
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   &db,
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   &filter_policy);
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!s.ok()) {
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString();
330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return scoped_ptr<LevelDBDatabase>();
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<LevelDBDatabase> result(new LevelDBDatabase);
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  result->env_ = in_memory_env.Pass();
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  result->db_ = make_scoped_ptr(db);
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  result->comparator_adapter_ = comparator_adapter.Pass();
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  result->comparator_ = comparator;
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  result->filter_policy_ = filter_policy.Pass();
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return result.Pass();
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status LevelDBDatabase::Put(const StringPiece& key,
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     std::string* value) {
3456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::TimeTicks begin_time = base::TimeTicks::Now();
3466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::WriteOptions write_options;
3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  write_options.sync = kSyncWrites;
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const leveldb::Status s =
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      db_->Put(write_options, MakeSlice(key), MakeSlice(*value));
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok())
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "LevelDB put failed: " << s.ToString();
3546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  else
3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.PutTime",
3566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        base::TimeTicks::Now() - begin_time);
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return s;
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status LevelDBDatabase::Remove(const StringPiece& key) {
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::WriteOptions write_options;
3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  write_options.sync = kSyncWrites;
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const leveldb::Status s = db_->Delete(write_options, MakeSlice(key));
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.IsNotFound())
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return s;
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status LevelDBDatabase::Get(const StringPiece& key,
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     std::string* value,
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     bool* found,
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     const LevelDBSnapshot* snapshot) {
374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *found = false;
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::ReadOptions read_options;
376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  read_options.verify_checksums = true;  // TODO(jsbell): Disable this if the
377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                         // performance impact is too great.
378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const leveldb::Status s = db_->Get(read_options, MakeSlice(key), value);
381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (s.ok()) {
382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    *found = true;
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return s;
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (s.IsNotFound())
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return leveldb::Status::OK();
3877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  HistogramLevelDBError("WebCore.IndexedDB.LevelDBReadErrors", s);
388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LOG(ERROR) << "LevelDB get failed: " << s.ToString();
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return s;
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status LevelDBDatabase::Write(const LevelDBWriteBatch& write_batch) {
3936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  base::TimeTicks begin_time = base::TimeTicks::Now();
394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::WriteOptions write_options;
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  write_options.sync = kSyncWrites;
396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const leveldb::Status s =
398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      db_->Write(write_options, write_batch.write_batch_.get());
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    HistogramLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s);
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "LevelDB write failed: " << s.ToString();
4026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  } else {
4036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.WriteTime",
4046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                        base::TimeTicks::Now() - begin_time);
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return s;
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator(
410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const LevelDBSnapshot* snapshot) {
411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  leveldb::ReadOptions read_options;
412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  read_options.verify_checksums = true;  // TODO(jsbell): Disable this if the
413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                         // performance impact is too great.
414868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<leveldb::Iterator> i(db_->NewIterator(read_options));
417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return scoped_ptr<LevelDBIterator>(
418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      IndexedDBClassFactory::Get()->CreateIteratorImpl(i.Pass()));
419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
421868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const LevelDBComparator* LevelDBDatabase::Comparator() const {
422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return comparator_;
423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void LevelDBDatabase::Compact(const base::StringPiece& start,
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const base::StringPiece& stop) {
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Slice start_slice = MakeSlice(start);
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const leveldb::Slice stop_slice = MakeSlice(stop);
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // NULL batch means just wait for earlier writes to be done
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  db_->Write(leveldb::WriteOptions(), NULL);
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  db_->CompactRange(&start_slice, &stop_slice);
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
434e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid LevelDBDatabase::CompactAll() { db_->CompactRange(NULL, NULL); }
435e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
436868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
437