Chromium Code Reviews| 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::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 | |
| OLD | NEW |