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

Side by Side Diff: services/url_response_disk_cache/url_response_disk_cache_db.cc

Issue 1276073004: Offline By Default (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Use memcpy to solve alignment issue. Created 5 years, 3 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
OLDNEW
(Empty)
1 // Copyright 2015 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 "services/url_response_disk_cache/url_response_disk_cache_db.h"
6
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/time/time.h"
10 #include "leveldb/comparator.h"
11 #include "leveldb/db.h"
12 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
13 #include "services/url_response_disk_cache/url_response_disk_cache_entry.mojom.h "
14
15 namespace mojo {
16 namespace {
17
18 const char kVersionKey[] = "/version";
19
20 // TODO(darin): These Serialize / Deserialize methods should not live here.
21 // They use private details of the bindings system. Instead, we should provide
22 // these as helper functions under mojo/public/cpp/bindings/.
23
24 template <typename T>
25 void Serialize(T input, std::string* output) {
26 typedef typename mojo::internal::WrapperTraits<T>::DataType DataType;
27 size_t size = GetSerializedSize_(input);
28
29 output->clear();
30 output->resize(size);
31
32 mojo::internal::FixedBuffer buf;
33 buf.Initialize(&output->at(0), size);
34
35 DataType data_type;
36 Serialize_(input.Pass(), &buf, &data_type);
37 std::vector<Handle> handles;
38 data_type->EncodePointersAndHandles(&handles);
39 }
40
41 template <typename T>
42 bool Deserialize(void* data, size_t size, T* output) {
43 typedef typename mojo::internal::WrapperTraits<T>::DataType DataType;
44 mojo::internal::BoundsChecker bounds_checker(data, size, 0);
45 if (!std::remove_pointer<DataType>::type::Validate(data, &bounds_checker)) {
46 return false;
47 }
48 DataType data_type = reinterpret_cast<DataType>(data);
49 std::vector<Handle> handles;
50 data_type->DecodePointersAndHandles(&handles);
51 Deserialize_(data_type, output);
52 return true;
53 }
54
55 template <typename T>
56 bool Deserialize(std::string s, T* output) {
57 return Deserialize(&s.at(0), s.size(), output);
58 }
59
60 template <typename T>
61 bool Deserialize(const leveldb::Slice& s, T* output) {
62 return Deserialize(s.ToString(), output);
63 }
64
65 bool IsMetaDataKey(const leveldb::Slice& s) {
66 return s.size() != 0 && s[0] == '/';
67 }
68
69 class KeyComparator : public leveldb::Comparator {
70 public:
71 int Compare(const leveldb::Slice& s1,
72 const leveldb::Slice& s2) const override {
73 if (IsMetaDataKey(s1) != IsMetaDataKey(s2)) {
74 if (IsMetaDataKey(s1))
75 return -1;
76 return 1;
77 }
78
79 if (IsMetaDataKey(s1))
80 return leveldb::BytewiseComparator()->Compare(s1, s2);
81
82 mojo::LevelDBKeyPtr k1, k2;
83 bool result = Deserialize(s1, &k1) && Deserialize(s2, &k2);
84 DCHECK(result);
85 if (k1->request_origin.get() < k2->request_origin.get())
86 return -1;
87 if (k1->request_origin.get() > k2->request_origin.get())
88 return +1;
89 if (k1->url.get() < k2->url.get())
90 return -1;
91 if (k1->url.get() > k2->url.get())
92 return +1;
93 if (k1->timestamp < k2->timestamp)
94 return 1;
95 if (k1->timestamp > k2->timestamp)
96 return -1;
97 return 0;
98 }
99
100 const char* Name() const override { return "KeyComparator"; }
101 void FindShortestSeparator(std::string*,
102 const leveldb::Slice&) const override {}
103 void FindShortSuccessor(std::string*) const override {}
104 };
105
106 class DBIterator : public DBReader::Iterator {
107 public:
108 DBIterator(linked_ptr<leveldb::DB> db, const leveldb::ReadOptions& options);
109
110 private:
111 // Implementation of DBReader::Iterator:
112 bool HasNext() override;
113 void GetNext(LevelDBKeyPtr* key, CacheEntryPtr* entry) override;
114
115 linked_ptr<leveldb::DB> db_;
116 scoped_ptr<leveldb::Iterator> it_;
117 };
118
119 class DBReaderImpl : public DBReader {
120 public:
121 DBReaderImpl(linked_ptr<leveldb::DB> db, const leveldb::ReadOptions& options);
122 ~DBReaderImpl() override;
123
124 private:
125 // Implementation of DBReader:
126 scoped_ptr<Iterator> Iterate() override;
127 CacheEntryPtr Get(const std::string& request_origin,
128 const std::string& url) override;
129
130 linked_ptr<leveldb::DB> db_;
131 leveldb::ReadOptions options_;
132 };
133
134 class DBSnapshot : public DBReader {
135 public:
136 DBSnapshot(linked_ptr<leveldb::DB> db);
137 ~DBSnapshot() override;
138
139 private:
140 // Implementation of DBReader:
141 scoped_ptr<Iterator> Iterate() override;
142 CacheEntryPtr Get(const std::string& request_origin,
143 const std::string& url) override;
144
145 linked_ptr<leveldb::DB> db_;
146 leveldb::ReadOptions options_;
147 scoped_ptr<DBReader> db_reader_;
148 };
149
150 DBIterator::DBIterator(linked_ptr<leveldb::DB> db,
151 const leveldb::ReadOptions& options)
152 : db_(db) {
153 it_.reset(db_->NewIterator(options));
154 it_->SeekToFirst();
155 }
156
157 bool DBIterator::HasNext() {
158 while (it_->Valid() && IsMetaDataKey(it_->key())) {
159 it_->Next();
160 }
161 return it_->Valid();
162 }
163
164 void DBIterator::GetNext(LevelDBKeyPtr* key, CacheEntryPtr* entry) {
165 DCHECK(it_->Valid());
166 if (key)
167 Deserialize(it_->key(), key);
168 if (entry)
169 Deserialize(it_->value(), entry);
170 it_->Next();
171 }
172
173 DBReaderImpl::DBReaderImpl(linked_ptr<leveldb::DB> db,
174 const leveldb::ReadOptions& options)
175 : db_(db), options_(options) {}
176
177 // virtual
178 DBReaderImpl::~DBReaderImpl() {}
179
180 scoped_ptr<DBReader::Iterator> DBReaderImpl::Iterate() {
181 return make_scoped_ptr(new DBIterator(db_, options_));
182 }
183
184 CacheEntryPtr DBReaderImpl::Get(const std::string& request_origin,
185 const std::string& url) {
186 LevelDBKeyPtr key = LevelDBKey::New();
187 key->request_origin = request_origin;
188 key->url = url;
189 key->timestamp = std::numeric_limits<int64>::max();
190 std::string key_string;
191 Serialize(key.Pass(), &key_string);
192 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options_));
193 it->Seek(key_string);
194 CacheEntryPtr result;
195 if (it->Valid()) {
196 Deserialize(it->key(), &key);
197 if (key->request_origin == request_origin && key->url == url) {
198 Deserialize(it->value(), &result);
199 }
200 }
201 return result.Pass();
202 }
203
204 DBSnapshot::DBSnapshot(linked_ptr<leveldb::DB> db) : db_(db) {
205 options_.snapshot = db_->GetSnapshot();
206 db_reader_.reset(new DBReaderImpl(db, options_));
207 }
208
209 // virtual
210 DBSnapshot::~DBSnapshot() {
211 db_->ReleaseSnapshot(options_.snapshot);
212 }
213
214 scoped_ptr<DBReader::Iterator> DBSnapshot::Iterate() {
215 return db_reader_->Iterate();
216 }
217
218 CacheEntryPtr DBSnapshot::Get(const std::string& request_origin,
219 const std::string& url) {
220 return db_reader_->Get(request_origin, url);
221 }
222
223 } // namespace
224
225 URLResponseDiskCacheDB::URLResponseDiskCacheDB(const base::FilePath& db_path)
226 : comparator_(new KeyComparator) {
227 leveldb::DB* db;
228 leveldb::Options options;
229 options.create_if_missing = true;
230 options.comparator = comparator_.get();
231 leveldb::Status status = leveldb::DB::Open(options, db_path.value(), &db);
232 DCHECK(status.ok()) << status.ToString();
233 db_.reset(db);
234 db_reader_.reset(new DBReaderImpl(db_, leveldb::ReadOptions()));
235 }
236
237 // virtual
238 URLResponseDiskCacheDB::~URLResponseDiskCacheDB() {}
239
240 scoped_ptr<DBReader::Iterator> URLResponseDiskCacheDB::Iterate() {
241 return db_reader_->Iterate();
242 }
243
244 CacheEntryPtr URLResponseDiskCacheDB::Get(const std::string& request_origin,
245 const std::string& url) {
246 return db_reader_->Get(request_origin, url);
247 }
248
249 uint64_t URLResponseDiskCacheDB::GetVersion() {
250 std::string value;
251 leveldb::Status status =
252 db_->Get(leveldb::ReadOptions(), kVersionKey, &value);
253 if (status.IsNotFound())
254 return 0u;
255 DCHECK(status.ok());
256 uint64_t version;
257 memcpy(&version, value.data(), sizeof(version));
258 return version;
259 }
260
261 void URLResponseDiskCacheDB::SetVersion(uint64_t version) {
262 leveldb::Status status = db_->Put(
263 leveldb::WriteOptions(), kVersionKey,
264 leveldb::Slice(reinterpret_cast<char*>(&version), sizeof(version)));
265 DCHECK(status.ok());
266 }
267
268 void URLResponseDiskCacheDB::Put(const std::string& request_origin,
269 const std::string& url,
270 CacheEntryPtr entry) {
271 LevelDBKeyPtr key = LevelDBKey::New();
272 key->request_origin = request_origin;
273 key->url = url;
274 key->timestamp = base::Time::Now().ToInternalValue();
275 std::string key_string;
276 Serialize(key.Pass(), &key_string);
277 std::string entry_string;
278 Serialize(entry.Pass(), &entry_string);
279 leveldb::Status s =
280 db_->Put(leveldb::WriteOptions(), key_string, entry_string);
281 DCHECK(s.ok());
282 }
283
284 void URLResponseDiskCacheDB::Delete(LevelDBKeyPtr key) {
285 std::string key_string;
286 Serialize(key.Pass(), &key_string);
287 leveldb::Status s = db_->Delete(leveldb::WriteOptions(), key_string);
288 DCHECK(s.ok());
289 }
290
291 scoped_ptr<DBReader> URLResponseDiskCacheDB::GetSnapshot() {
292 return make_scoped_ptr(new DBSnapshot(db_));
293 }
294
295 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698