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

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

Powered by Google App Engine
This is Rietveld 408576698