Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Side by Side Diff: content/browser/indexed_db/leveldb/leveldb_database.cc

Issue 15659013: Revert "Migrate the IndexedDB backend from Blink to Chromium" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_database.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram.h"
13 #include "base/string16.h"
14 #include "base/sys_info.h"
15 #include "base/utf_string_conversions.h"
16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
17 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
18 #include "content/browser/indexed_db/leveldb/leveldb_slice.h"
19 #include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
20 #include "third_party/leveldatabase/env_idb.h"
21 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
22 #include "third_party/leveldatabase/src/include/leveldb/comparator.h"
23 #include "third_party/leveldatabase/src/include/leveldb/db.h"
24 #include "third_party/leveldatabase/src/include/leveldb/env.h"
25 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
26
27 namespace content {
28
29 static leveldb::Slice MakeSlice(const std::vector<char>& value) {
30 return leveldb::Slice(&*value.begin(), value.size());
31 }
32
33 static leveldb::Slice MakeSlice(const LevelDBSlice& s) {
34 return leveldb::Slice(s.begin(), s.end() - s.begin());
35 }
36
37 static LevelDBSlice MakeLevelDBSlice(const leveldb::Slice& s) {
38 return LevelDBSlice(s.data(), s.data() + s.size());
39 }
40
41 class ComparatorAdapter : public leveldb::Comparator {
42 public:
43 explicit ComparatorAdapter(const LevelDBComparator* comparator)
44 : comparator_(comparator) {}
45
46 virtual int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const
47 OVERRIDE {
48 return comparator_->Compare(MakeLevelDBSlice(a), MakeLevelDBSlice(b));
49 }
50
51 virtual const char* Name() const OVERRIDE { return comparator_->Name(); }
52
53 // TODO(jsbell): Support the methods below in the future.
54 virtual void FindShortestSeparator(std::string* start,
55 const leveldb::Slice& limit) const
56 OVERRIDE {}
57 virtual void FindShortSuccessor(std::string* key) const OVERRIDE {}
58
59 private:
60 const LevelDBComparator* comparator_;
61 };
62
63 LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db)
64 : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {}
65
66 LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); }
67
68 LevelDBDatabase::LevelDBDatabase() {}
69
70 LevelDBDatabase::~LevelDBDatabase() {
71 // db_'s destructor uses comparator_adapter_; order of deletion is important.
72 db_.reset();
73 comparator_adapter_.reset();
74 env_.reset();
75 }
76
77 static leveldb::Status OpenDB(leveldb::Comparator* comparator,
78 leveldb::Env* env,
79 const base::FilePath& path,
80 leveldb::DB** db) {
81 leveldb::Options options;
82 options.comparator = comparator;
83 options.create_if_missing = true;
84 options.paranoid_checks = true;
85
86 // Marking compression as explicitly off so snappy support can be
87 // compiled in for other leveldb clients without implicitly enabling
88 // it for IndexedDB. http://crbug.com/81384
89 options.compression = leveldb::kNoCompression;
90
91 // 20 max_open_files is the minimum LevelDB allows but its cache behaves
92 // poorly with less than 4 files per shard. As of this writing the latest
93 // leveldb (1.9) hardcodes 16 shards. See
94 // https://code.google.com/p/chromium/issues/detail?id=227313#c11
95 options.max_open_files = 80;
96 options.env = env;
97
98 // ChromiumEnv assumes UTF8, converts back to FilePath before using.
99 return leveldb::DB::Open(options, path.AsUTF8Unsafe(), db);
100 }
101
102 bool LevelDBDatabase::Destroy(const base::FilePath& file_name) {
103 leveldb::Options options;
104 options.env = leveldb::IDBEnv();
105 // ChromiumEnv assumes UTF8, converts back to FilePath before using.
106 const leveldb::Status s =
107 leveldb::DestroyDB(file_name.AsUTF8Unsafe(), options);
108 return s.ok();
109 }
110
111 static void HistogramFreeSpace(const char* type,
112 const base::FilePath& file_name) {
113 string16 name = ASCIIToUTF16("WebCore.IndexedDB.LevelDB.Open") +
114 ASCIIToUTF16(type) + ASCIIToUTF16("FreeDiskSpace");
115 int64 free_disk_space_in_k_bytes =
116 base::SysInfo::AmountOfFreeDiskSpace(file_name) / 1024;
117 if (free_disk_space_in_k_bytes < 0) {
118 base::Histogram::FactoryGet(
119 "WebCore.IndexedDB.LevelDB.FreeDiskSpaceFailure",
120 1,
121 2 /*boundary*/,
122 2 /*boundary*/ + 1,
123 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(1 /*sample*/);
124 return;
125 }
126 int clamped_disk_space_k_bytes =
127 free_disk_space_in_k_bytes > INT_MAX ? INT_MAX
128 : free_disk_space_in_k_bytes;
129 const uint64 histogram_max = static_cast<uint64>(1e9);
130 COMPILE_ASSERT(histogram_max <= INT_MAX, histogram_max_too_big);
131 base::Histogram::FactoryGet(UTF16ToUTF8(name),
132 1,
133 histogram_max,
134 11 /*buckets*/,
135 base::HistogramBase::kUmaTargetedHistogramFlag)
136 ->Add(clamped_disk_space_k_bytes);
137 }
138
139 static void HistogramLevelDBError(const char* histogram_name,
140 const leveldb::Status& s) {
141 DCHECK(!s.ok());
142 enum {
143 LEVEL_DB_NOT_FOUND,
144 LEVEL_DB_CORRUPTION,
145 LEVEL_DB_IO_ERROR,
146 LEVEL_DB_OTHER,
147 LEVEL_DB_MAX_ERROR
148 };
149 int leveldb_error = LEVEL_DB_OTHER;
150 if (s.IsNotFound())
151 leveldb_error = LEVEL_DB_NOT_FOUND;
152 else if (s.IsCorruption())
153 leveldb_error = LEVEL_DB_CORRUPTION;
154 else if (s.IsIOError())
155 leveldb_error = LEVEL_DB_IO_ERROR;
156 base::Histogram::FactoryGet(histogram_name,
157 1,
158 LEVEL_DB_MAX_ERROR,
159 LEVEL_DB_MAX_ERROR + 1,
160 base::HistogramBase::kUmaTargetedHistogramFlag)
161 ->Add(leveldb_error);
162 }
163
164 scoped_ptr<LevelDBDatabase> LevelDBDatabase::Open(
165 const base::FilePath& file_name,
166 const LevelDBComparator* comparator) {
167 scoped_ptr<ComparatorAdapter> comparator_adapter(
168 new ComparatorAdapter(comparator));
169
170 leveldb::DB* db;
171 const leveldb::Status s =
172 OpenDB(comparator_adapter.get(), leveldb::IDBEnv(), file_name, &db);
173
174 if (!s.ok()) {
175 HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s);
176 HistogramFreeSpace("Failure", file_name);
177
178 LOG(ERROR) << "Failed to open LevelDB database from "
179 << file_name.AsUTF8Unsafe() << "," << s.ToString();
180 return scoped_ptr<LevelDBDatabase>();
181 }
182
183 HistogramFreeSpace("Success", file_name);
184
185 scoped_ptr<LevelDBDatabase> result(new LevelDBDatabase);
186 result->db_ = make_scoped_ptr(db);
187 result->comparator_adapter_ = comparator_adapter.Pass();
188 result->comparator_ = comparator;
189
190 return result.Pass();
191 }
192
193 scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
194 const LevelDBComparator* comparator) {
195 scoped_ptr<ComparatorAdapter> comparator_adapter(
196 new ComparatorAdapter(comparator));
197 scoped_ptr<leveldb::Env> in_memory_env(leveldb::NewMemEnv(leveldb::IDBEnv()));
198
199 leveldb::DB* db;
200 const leveldb::Status s = OpenDB(
201 comparator_adapter.get(), in_memory_env.get(), base::FilePath(), &db);
202
203 if (!s.ok()) {
204 LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString();
205 return scoped_ptr<LevelDBDatabase>();
206 }
207
208 scoped_ptr<LevelDBDatabase> result(new LevelDBDatabase);
209 result->env_ = in_memory_env.Pass();
210 result->db_ = make_scoped_ptr(db);
211 result->comparator_adapter_ = comparator_adapter.Pass();
212 result->comparator_ = comparator;
213
214 return result.Pass();
215 }
216
217 bool LevelDBDatabase::Put(const LevelDBSlice& key,
218 const std::vector<char>& value) {
219 leveldb::WriteOptions write_options;
220 write_options.sync = true;
221
222 const leveldb::Status s =
223 db_->Put(write_options, MakeSlice(key), MakeSlice(value));
224 if (s.ok())
225 return true;
226 LOG(ERROR) << "LevelDB put failed: " << s.ToString();
227 return false;
228 }
229
230 bool LevelDBDatabase::Remove(const LevelDBSlice& key) {
231 leveldb::WriteOptions write_options;
232 write_options.sync = true;
233
234 const leveldb::Status s = db_->Delete(write_options, MakeSlice(key));
235 if (s.ok())
236 return true;
237 if (s.IsNotFound())
238 return false;
239 LOG(ERROR) << "LevelDB remove failed: " << s.ToString();
240 return false;
241 }
242
243 bool LevelDBDatabase::Get(const LevelDBSlice& key,
244 std::vector<char>& value,
245 bool& found,
246 const LevelDBSnapshot* snapshot) {
247 found = false;
248 std::string result;
249 leveldb::ReadOptions read_options;
250 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the
251 // performance impact is too great.
252 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
253
254 const leveldb::Status s = db_->Get(read_options, MakeSlice(key), &result);
255 if (s.ok()) {
256 found = true;
257 value.clear();
258 value.insert(value.end(), result.begin(), result.end());
259 return true;
260 }
261 if (s.IsNotFound())
262 return true;
263 LOG(ERROR) << "LevelDB get failed: " << s.ToString();
264 return false;
265 }
266
267 bool LevelDBDatabase::Write(LevelDBWriteBatch& write_batch) {
268 leveldb::WriteOptions write_options;
269 write_options.sync = true;
270
271 const leveldb::Status s =
272 db_->Write(write_options, write_batch.write_batch_.get());
273 if (s.ok())
274 return true;
275 HistogramLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s);
276 LOG(ERROR) << "LevelDB write failed: " << s.ToString();
277 return false;
278 }
279
280 namespace {
281 class IteratorImpl : public LevelDBIterator {
282 public:
283 virtual ~IteratorImpl() {}
284
285 virtual bool IsValid() const OVERRIDE;
286 virtual void SeekToLast() OVERRIDE;
287 virtual void Seek(const LevelDBSlice& target) OVERRIDE;
288 virtual void Next() OVERRIDE;
289 virtual void Prev() OVERRIDE;
290 virtual LevelDBSlice Key() const OVERRIDE;
291 virtual LevelDBSlice Value() const OVERRIDE;
292
293 private:
294 friend class content::LevelDBDatabase;
295 IteratorImpl(scoped_ptr<leveldb::Iterator> iterator);
296 void CheckStatus();
297
298 scoped_ptr<leveldb::Iterator> iterator_;
299 };
300 }
301
302 IteratorImpl::IteratorImpl(scoped_ptr<leveldb::Iterator> it)
303 : iterator_(it.Pass()) {}
304
305 void IteratorImpl::CheckStatus() {
306 const leveldb::Status s = iterator_->status();
307 if (!s.ok())
308 LOG(ERROR) << "LevelDB iterator error: " << s.ToString();
309 }
310
311 bool IteratorImpl::IsValid() const { return iterator_->Valid(); }
312
313 void IteratorImpl::SeekToLast() {
314 iterator_->SeekToLast();
315 CheckStatus();
316 }
317
318 void IteratorImpl::Seek(const LevelDBSlice& target) {
319 iterator_->Seek(MakeSlice(target));
320 CheckStatus();
321 }
322
323 void IteratorImpl::Next() {
324 DCHECK(IsValid());
325 iterator_->Next();
326 CheckStatus();
327 }
328
329 void IteratorImpl::Prev() {
330 DCHECK(IsValid());
331 iterator_->Prev();
332 CheckStatus();
333 }
334
335 LevelDBSlice IteratorImpl::Key() const {
336 DCHECK(IsValid());
337 return MakeLevelDBSlice(iterator_->key());
338 }
339
340 LevelDBSlice IteratorImpl::Value() const {
341 DCHECK(IsValid());
342 return MakeLevelDBSlice(iterator_->value());
343 }
344
345 scoped_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator(
346 const LevelDBSnapshot* snapshot) {
347 leveldb::ReadOptions read_options;
348 read_options.verify_checksums = true; // TODO(jsbell): Disable this if the
349 // performance impact is too great.
350 read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
351 scoped_ptr<leveldb::Iterator> i(db_->NewIterator(read_options));
352 if (!i) // TODO(jsbell): Double check if we actually need to check this.
353 return scoped_ptr<LevelDBIterator>();
354 return scoped_ptr<LevelDBIterator>(new IteratorImpl(i.Pass()));
355 }
356
357 const LevelDBComparator* LevelDBDatabase::Comparator() const {
358 return comparator_;
359 }
360
361 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/leveldb/leveldb_database.h ('k') | content/browser/indexed_db/leveldb/leveldb_iterator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698