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 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 |
OLD | NEW |