OLD | NEW |
---|---|
(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/time/time.h" | |
9 #include "leveldb/comparator.h" | |
10 #include "leveldb/db.h" | |
11 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" | |
12 #include "services/url_response_disk_cache/url_response_disk_cache_entry.mojom.h " | |
13 | |
14 namespace mojo { | |
15 namespace { | |
16 | |
17 const char kVersionKey[] = "/version"; | |
18 | |
19 union VersionData { | |
20 uint64_t version; | |
21 char data[sizeof(uint64_t)]; | |
22 }; | |
23 | |
24 // TODO(darin): These Serialize / Deserialize methods should not live here. | |
25 // They use private details of the bindings system. Instead, we should provide | |
26 // these as helper functions under mojo/public/cpp/bindings/. | |
27 | |
28 template <typename T> | |
29 void Serialize(T input, std::string* output) { | |
30 typedef typename mojo::internal::WrapperTraits<T>::DataType DataType; | |
31 size_t size = GetSerializedSize_(input); | |
32 | |
33 output->clear(); | |
34 output->resize(size); | |
35 | |
36 mojo::internal::FixedBuffer buf; | |
37 buf.Initialize(&output->at(0), size); | |
38 | |
39 DataType data_type; | |
40 Serialize_(input.Pass(), &buf, &data_type); | |
41 std::vector<Handle> handles; | |
42 data_type->EncodePointersAndHandles(&handles); | |
43 } | |
44 | |
45 template <typename T> | |
46 bool Deserialize(void* data, size_t size, T* output) { | |
47 typedef typename mojo::internal::WrapperTraits<T>::DataType DataType; | |
48 mojo::internal::BoundsChecker bounds_checker(data, size, 0); | |
49 if (!std::remove_pointer<DataType>::type::Validate(data, &bounds_checker)) { | |
50 return false; | |
51 } | |
52 DataType data_type = reinterpret_cast<DataType>(data); | |
53 std::vector<Handle> handles; | |
54 data_type->DecodePointersAndHandles(&handles); | |
55 Deserialize_(data_type, output); | |
56 return true; | |
57 } | |
58 | |
59 template <typename T> | |
60 bool Deserialize(std::string s, T* output) { | |
61 return Deserialize(&s.at(0), s.size(), output); | |
62 } | |
63 | |
64 template <typename T> | |
65 bool Deserialize(const leveldb::Slice& s, T* output) { | |
66 return Deserialize(s.ToString(), output); | |
67 } | |
68 | |
69 bool IsMetaDataKey(const leveldb::Slice& s) { | |
ppi
2015/09/08 11:56:24
Please describe what meta data key is, maybe give
qsr
2015/09/08 13:35:22
Comment added.
| |
70 return s.size() != 0 && s[0] == '/'; | |
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::LevelDBKeyPtr 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 { | |
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(LevelDBKeyPtr* 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(LevelDBKeyPtr* 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 LevelDBKeyPtr key = LevelDBKey::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 | |
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 const VersionData* version_data = | |
261 reinterpret_cast<const VersionData*>(value.data()); | |
262 return version_data->version; | |
263 } | |
264 | |
265 void URLResponseDiskCacheDB::SetVersion(uint64_t version) { | |
266 VersionData version_data; | |
267 version_data.version = version; | |
268 leveldb::Status status = | |
269 db_->Put(leveldb::WriteOptions(), kVersionKey, | |
270 leveldb::Slice(version_data.data, sizeof(version))); | |
271 DCHECK(status.ok()); | |
272 } | |
273 | |
274 void URLResponseDiskCacheDB::Put(const std::string& request_origin, | |
275 const std::string& url, | |
276 CacheEntryPtr entry) { | |
277 LevelDBKeyPtr key = LevelDBKey::New(); | |
278 key->request_origin = request_origin; | |
279 key->url = url; | |
280 key->timestamp = base::Time::Now().ToInternalValue(); | |
281 std::string key_string; | |
282 Serialize(key.Pass(), &key_string); | |
283 std::string entry_string; | |
284 Serialize(entry.Pass(), &entry_string); | |
285 leveldb::Status s = | |
286 db_->Put(leveldb::WriteOptions(), key_string, entry_string); | |
287 DCHECK(s.ok()); | |
288 } | |
289 | |
290 void URLResponseDiskCacheDB::Delete(LevelDBKeyPtr key) { | |
291 std::string key_string; | |
292 Serialize(key.Pass(), &key_string); | |
293 leveldb::Status s = db_->Delete(leveldb::WriteOptions(), key_string); | |
294 DCHECK(s.ok()); | |
295 } | |
296 | |
297 scoped_ptr<DBReader> URLResponseDiskCacheDB::GetSnapshot() { | |
298 return make_scoped_ptr(new DBSnapshot(db_)); | |
299 } | |
300 | |
301 } // namespace mojo | |
OLD | NEW |