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

Unified 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: Fix command line. 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 side-by-side diff with in-line comments
Download patch
Index: services/url_response_disk_cache/url_response_disk_cache_db.cc
diff --git a/services/url_response_disk_cache/url_response_disk_cache_db.cc b/services/url_response_disk_cache/url_response_disk_cache_db.cc
new file mode 100644
index 0000000000000000000000000000000000000000..83c7afc03025b99a29483ed5b2c865328b7659b4
--- /dev/null
+++ b/services/url_response_disk_cache/url_response_disk_cache_db.cc
@@ -0,0 +1,301 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/url_response_disk_cache/url_response_disk_cache_db.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "leveldb/comparator.h"
+#include "leveldb/db.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "services/url_response_disk_cache/url_response_disk_cache_entry.mojom.h"
+
+namespace mojo {
+namespace {
+
+const char kVersionKey[] = "/version";
+
+union VersionData {
+ uint64_t version;
+ char data[sizeof(uint64_t)];
+};
+
+// TODO(darin): These Serialize / Deserialize methods should not live here.
+// They use private details of the bindings system. Instead, we should provide
+// these as helper functions under mojo/public/cpp/bindings/.
+
+template <typename T>
+void Serialize(T input, std::string* output) {
+ typedef typename mojo::internal::WrapperTraits<T>::DataType DataType;
+ size_t size = GetSerializedSize_(input);
+
+ output->clear();
+ output->resize(size);
+
+ mojo::internal::FixedBuffer buf;
+ buf.Initialize(&output->at(0), size);
+
+ DataType data_type;
+ Serialize_(input.Pass(), &buf, &data_type);
+ std::vector<Handle> handles;
+ data_type->EncodePointersAndHandles(&handles);
+}
+
+template <typename T>
+bool Deserialize(void* data, size_t size, T* output) {
+ typedef typename mojo::internal::WrapperTraits<T>::DataType DataType;
+ mojo::internal::BoundsChecker bounds_checker(data, size, 0);
+ if (!std::remove_pointer<DataType>::type::Validate(data, &bounds_checker)) {
+ return false;
+ }
+ DataType data_type = reinterpret_cast<DataType>(data);
+ std::vector<Handle> handles;
+ data_type->DecodePointersAndHandles(&handles);
+ Deserialize_(data_type, output);
+ return true;
+}
+
+template <typename T>
+bool Deserialize(std::string s, T* output) {
+ return Deserialize(&s.at(0), s.size(), output);
+}
+
+template <typename T>
+bool Deserialize(const leveldb::Slice& s, T* output) {
+ return Deserialize(s.ToString(), output);
+}
+
+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.
+ return s.size() != 0 && s[0] == '/';
+}
+
+class KeyComparator : public leveldb::Comparator {
+ public:
+ int Compare(const leveldb::Slice& s1,
+ const leveldb::Slice& s2) const override {
+ if (IsMetaDataKey(s1) != IsMetaDataKey(s2)) {
+ if (IsMetaDataKey(s1))
+ return -1;
+ return 1;
+ }
+
+ if (IsMetaDataKey(s1))
+ return leveldb::BytewiseComparator()->Compare(s1, s2);
+
+ mojo::LevelDBKeyPtr k1, k2;
+ bool result = Deserialize(s1, &k1) && Deserialize(s2, &k2);
+ DCHECK(result);
+ if (k1->request_origin.get() < k2->request_origin.get())
+ return -1;
+ if (k1->request_origin.get() > k2->request_origin.get())
+ return +1;
+ if (k1->url.get() < k2->url.get())
+ return -1;
+ if (k1->url.get() > k2->url.get())
+ return +1;
+ if (k1->timestamp < k2->timestamp)
+ return 1;
+ if (k1->timestamp > k2->timestamp)
+ return -1;
+ return 0;
+ }
+
+ const char* Name() const override { return "KeyComparator"; }
+ void FindShortestSeparator(std::string*,
+ const leveldb::Slice&) const override {}
+ void FindShortSuccessor(std::string*) const override {}
+};
+
+class DBIterator : public DBReader::Iterator {
+ public:
+ DBIterator(linked_ptr<leveldb::DB> db, const leveldb::ReadOptions& options);
+
+ private:
+ // Implementation of DBReader::Iterator:
+ bool HasNext() override;
+ void GetNext(LevelDBKeyPtr* key, CacheEntryPtr* entry) override;
+
+ linked_ptr<leveldb::DB> db_;
+ scoped_ptr<leveldb::Iterator> it_;
+};
+
+class DBReaderImpl : public DBReader {
+ public:
+ DBReaderImpl(linked_ptr<leveldb::DB> db, const leveldb::ReadOptions& options);
+ ~DBReaderImpl() override;
+
+ private:
+ // Implementation of DBReader:
+ scoped_ptr<Iterator> Iterate() override;
+ CacheEntryPtr Get(const std::string& request_origin,
+ const std::string& url) override;
+
+ linked_ptr<leveldb::DB> db_;
+ leveldb::ReadOptions options_;
+};
+
+class DBSnapshot : public DBReader {
+ public:
+ DBSnapshot(linked_ptr<leveldb::DB> db);
+ ~DBSnapshot() override;
+
+ private:
+ // Implementation of DBReader:
+ scoped_ptr<Iterator> Iterate() override;
+ CacheEntryPtr Get(const std::string& request_origin,
+ const std::string& url) override;
+
+ linked_ptr<leveldb::DB> db_;
+ leveldb::ReadOptions options_;
+ scoped_ptr<DBReader> db_reader_;
+};
+
+DBIterator::DBIterator(linked_ptr<leveldb::DB> db,
+ const leveldb::ReadOptions& options)
+ : db_(db) {
+ it_.reset(db_->NewIterator(options));
+ it_->SeekToFirst();
+}
+
+bool DBIterator::HasNext() {
+ while (it_->Valid() && IsMetaDataKey(it_->key())) {
+ it_->Next();
+ }
+ return it_->Valid();
+}
+
+void DBIterator::GetNext(LevelDBKeyPtr* key, CacheEntryPtr* entry) {
+ DCHECK(it_->Valid());
+ if (key)
+ Deserialize(it_->key(), key);
+ if (entry)
+ Deserialize(it_->value(), entry);
+ it_->Next();
+}
+
+DBReaderImpl::DBReaderImpl(linked_ptr<leveldb::DB> db,
+ const leveldb::ReadOptions& options)
+ : db_(db), options_(options) {}
+
+// virtual
+DBReaderImpl::~DBReaderImpl() {}
+
+scoped_ptr<DBReader::Iterator> DBReaderImpl::Iterate() {
+ return make_scoped_ptr(new DBIterator(db_, options_));
+}
+
+CacheEntryPtr DBReaderImpl::Get(const std::string& request_origin,
+ const std::string& url) {
+ LevelDBKeyPtr key = LevelDBKey::New();
+ key->request_origin = request_origin;
+ key->url = url;
+ key->timestamp = std::numeric_limits<int64>::max();
+ std::string key_string;
+ Serialize(key.Pass(), &key_string);
+ scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options_));
+ it->Seek(key_string);
+ CacheEntryPtr result;
+ if (it->Valid()) {
+ Deserialize(it->key(), &key);
+ if (key->request_origin == request_origin && key->url == url) {
+ Deserialize(it->value(), &result);
+ }
+ }
+ return result.Pass();
+}
+
+DBSnapshot::DBSnapshot(linked_ptr<leveldb::DB> db) : db_(db) {
+ options_.snapshot = db_->GetSnapshot();
+ db_reader_.reset(new DBReaderImpl(db, options_));
+}
+
+// virtual
+DBSnapshot::~DBSnapshot() {
+ db_->ReleaseSnapshot(options_.snapshot);
+}
+
+scoped_ptr<DBReader::Iterator> DBSnapshot::Iterate() {
+ return db_reader_->Iterate();
+}
+
+CacheEntryPtr DBSnapshot::Get(const std::string& request_origin,
+ const std::string& url) {
+ return db_reader_->Get(request_origin, url);
+}
+
+} // namespace
+
+URLResponseDiskCacheDB::URLResponseDiskCacheDB(const base::FilePath& db_path)
+ : comparator_(new KeyComparator) {
+ leveldb::DB* db;
+ leveldb::Options options;
+ options.create_if_missing = true;
+ options.comparator = comparator_.get();
+ leveldb::Status status = leveldb::DB::Open(options, db_path.value(), &db);
+ DCHECK(status.ok()) << status.ToString();
+ db_.reset(db);
+ db_reader_.reset(new DBReaderImpl(db_, leveldb::ReadOptions()));
+}
+
+// virtual
+URLResponseDiskCacheDB::~URLResponseDiskCacheDB() {}
+
+scoped_ptr<DBReader::Iterator> URLResponseDiskCacheDB::Iterate() {
+ return db_reader_->Iterate();
+}
+
+CacheEntryPtr URLResponseDiskCacheDB::Get(const std::string& request_origin,
+ const std::string& url) {
+ return db_reader_->Get(request_origin, url);
+}
+
+uint64_t URLResponseDiskCacheDB::GetVersion() {
+ std::string value;
+ leveldb::Status status =
+ db_->Get(leveldb::ReadOptions(), kVersionKey, &value);
+ if (status.IsNotFound())
+ return 0u;
+ DCHECK(status.ok());
+ const VersionData* version_data =
+ reinterpret_cast<const VersionData*>(value.data());
+ return version_data->version;
+}
+
+void URLResponseDiskCacheDB::SetVersion(uint64_t version) {
+ VersionData version_data;
+ version_data.version = version;
+ leveldb::Status status =
+ db_->Put(leveldb::WriteOptions(), kVersionKey,
+ leveldb::Slice(version_data.data, sizeof(version)));
+ DCHECK(status.ok());
+}
+
+void URLResponseDiskCacheDB::Put(const std::string& request_origin,
+ const std::string& url,
+ CacheEntryPtr entry) {
+ LevelDBKeyPtr key = LevelDBKey::New();
+ key->request_origin = request_origin;
+ key->url = url;
+ key->timestamp = base::Time::Now().ToInternalValue();
+ std::string key_string;
+ Serialize(key.Pass(), &key_string);
+ std::string entry_string;
+ Serialize(entry.Pass(), &entry_string);
+ leveldb::Status s =
+ db_->Put(leveldb::WriteOptions(), key_string, entry_string);
+ DCHECK(s.ok());
+}
+
+void URLResponseDiskCacheDB::Delete(LevelDBKeyPtr key) {
+ std::string key_string;
+ Serialize(key.Pass(), &key_string);
+ leveldb::Status s = db_->Delete(leveldb::WriteOptions(), key_string);
+ DCHECK(s.ok());
+}
+
+scoped_ptr<DBReader> URLResponseDiskCacheDB::GetSnapshot() {
+ return make_scoped_ptr(new DBSnapshot(db_));
+}
+
+} // namespace mojo

Powered by Google App Engine
This is Rietveld 408576698