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/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::CacheKeyPtr 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 } // namespace | |
111 | |
112 URLResponseDiskCacheDB::Iterator::Iterator(linked_ptr<leveldb::DB> db) | |
113 : db_(db) { | |
114 it_.reset(db_->NewIterator(leveldb::ReadOptions())); | |
115 it_->SeekToFirst(); | |
116 } | |
117 | |
118 URLResponseDiskCacheDB::Iterator::~Iterator() {} | |
119 | |
120 bool URLResponseDiskCacheDB::Iterator::HasNext() { | |
121 while (it_->Valid() && IsMetaDataKey(it_->key())) { | |
122 it_->Next(); | |
123 } | |
124 return it_->Valid(); | |
125 } | |
126 | |
127 void URLResponseDiskCacheDB::Iterator::GetNext(CacheKeyPtr* key, | |
ppi
2015/09/15 15:21:22
Do you want to either document that HasNext() need
qsr
2015/09/16 11:46:37
Done.
| |
128 CacheEntryPtr* entry) { | |
129 DCHECK(it_->Valid()); | |
130 if (key) | |
131 Deserialize(it_->key(), key); | |
132 if (entry) | |
133 Deserialize(it_->value(), entry); | |
134 it_->Next(); | |
135 } | |
136 | |
137 URLResponseDiskCacheDB::URLResponseDiskCacheDB(const base::FilePath& db_path) | |
138 : comparator_(new KeyComparator) { | |
139 leveldb::DB* db; | |
140 leveldb::Options options; | |
141 options.create_if_missing = true; | |
142 options.comparator = comparator_.get(); | |
143 leveldb::Status status = leveldb::DB::Open(options, db_path.value(), &db); | |
144 DCHECK(status.ok()) << status.ToString(); | |
145 db_.reset(db); | |
146 } | |
147 | |
148 uint64_t URLResponseDiskCacheDB::GetVersion() { | |
149 std::string value; | |
150 leveldb::Status status = | |
151 db_->Get(leveldb::ReadOptions(), kVersionKey, &value); | |
152 if (status.IsNotFound()) | |
153 return 0u; | |
154 DCHECK(status.ok()); | |
155 uint64_t version; | |
156 memcpy(&version, value.data(), sizeof(version)); | |
ppi
2015/09/15 15:21:22
should we include <string.h> for memcpy?
qsr
2015/09/16 11:46:37
Done.
| |
157 return version; | |
158 } | |
159 | |
160 void URLResponseDiskCacheDB::SetVersion(uint64_t version) { | |
161 leveldb::Status status = db_->Put( | |
162 leveldb::WriteOptions(), kVersionKey, | |
163 leveldb::Slice(reinterpret_cast<char*>(&version), sizeof(version))); | |
164 DCHECK(status.ok()); | |
165 } | |
166 | |
167 void URLResponseDiskCacheDB::PutNewest(const std::string& request_origin, | |
168 const std::string& url, | |
169 CacheEntryPtr entry) { | |
170 CacheKeyPtr key = CacheKey::New(); | |
171 key->request_origin = request_origin; | |
172 key->url = url; | |
173 key->timestamp = base::Time::Now().ToInternalValue(); | |
174 std::string key_string; | |
175 Serialize(key.Pass(), &key_string); | |
176 std::string entry_string; | |
177 Serialize(entry.Pass(), &entry_string); | |
178 leveldb::Status s = | |
179 db_->Put(leveldb::WriteOptions(), key_string, entry_string); | |
180 DCHECK(s.ok()); | |
181 } | |
182 | |
183 CacheEntryPtr URLResponseDiskCacheDB::GetNewest( | |
184 const std::string& request_origin, | |
185 const std::string& url) { | |
186 CacheKeyPtr key = CacheKey::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(leveldb::ReadOptions())); | |
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 void URLResponseDiskCacheDB::Delete(CacheKeyPtr key) { | |
205 std::string key_string; | |
206 Serialize(key.Pass(), &key_string); | |
207 leveldb::Status s = db_->Delete(leveldb::WriteOptions(), key_string); | |
208 DCHECK(s.ok()); | |
209 } | |
210 | |
211 scoped_ptr<URLResponseDiskCacheDB::Iterator> URLResponseDiskCacheDB::Iterate() { | |
212 return make_scoped_ptr(new Iterator(db_)); | |
213 } | |
214 | |
215 URLResponseDiskCacheDB::~URLResponseDiskCacheDB() {} | |
216 | |
217 } // namespace mojo | |
OLD | NEW |