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

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: Follow review 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..a2d36984032c569a90ec6138e29370b56ac878fb
--- /dev/null
+++ b/services/url_response_disk_cache/url_response_disk_cache_db.cc
@@ -0,0 +1,217 @@
+// 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/memory/scoped_ptr.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 {
+
+// List of keys for metadata. All metadata keys must start with a '\1'
+// character.
+const char kVersionKey[] = "\1version";
+
+// 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);
+}
+
+// Returns whether the key is for a metadata entry. Metadata entries are
+// declared at the start of this file.
+bool IsMetaDataKey(const leveldb::Slice& s) {
+ return s.size() != 0 && s[0] == '\1';
+}
+
+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::CacheKeyPtr 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 {}
+};
+
+} // namespace
+
+URLResponseDiskCacheDB::Iterator::Iterator(linked_ptr<leveldb::DB> db)
+ : db_(db) {
+ it_.reset(db_->NewIterator(leveldb::ReadOptions()));
+ it_->SeekToFirst();
+}
+
+URLResponseDiskCacheDB::Iterator::~Iterator() {}
+
+bool URLResponseDiskCacheDB::Iterator::HasNext() {
+ while (it_->Valid() && IsMetaDataKey(it_->key())) {
+ it_->Next();
+ }
+ return it_->Valid();
+}
+
+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.
+ CacheEntryPtr* entry) {
+ DCHECK(it_->Valid());
+ if (key)
+ Deserialize(it_->key(), key);
+ if (entry)
+ Deserialize(it_->value(), entry);
+ it_->Next();
+}
+
+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);
+}
+
+uint64_t URLResponseDiskCacheDB::GetVersion() {
+ std::string value;
+ leveldb::Status status =
+ db_->Get(leveldb::ReadOptions(), kVersionKey, &value);
+ if (status.IsNotFound())
+ return 0u;
+ DCHECK(status.ok());
+ uint64_t version;
+ 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.
+ return version;
+}
+
+void URLResponseDiskCacheDB::SetVersion(uint64_t version) {
+ leveldb::Status status = db_->Put(
+ leveldb::WriteOptions(), kVersionKey,
+ leveldb::Slice(reinterpret_cast<char*>(&version), sizeof(version)));
+ DCHECK(status.ok());
+}
+
+void URLResponseDiskCacheDB::PutNewest(const std::string& request_origin,
+ const std::string& url,
+ CacheEntryPtr entry) {
+ CacheKeyPtr key = CacheKey::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());
+}
+
+CacheEntryPtr URLResponseDiskCacheDB::GetNewest(
+ const std::string& request_origin,
+ const std::string& url) {
+ CacheKeyPtr key = CacheKey::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(leveldb::ReadOptions()));
+ 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();
+}
+
+void URLResponseDiskCacheDB::Delete(CacheKeyPtr key) {
+ std::string key_string;
+ Serialize(key.Pass(), &key_string);
+ leveldb::Status s = db_->Delete(leveldb::WriteOptions(), key_string);
+ DCHECK(s.ok());
+}
+
+scoped_ptr<URLResponseDiskCacheDB::Iterator> URLResponseDiskCacheDB::Iterate() {
+ return make_scoped_ptr(new Iterator(db_));
+}
+
+URLResponseDiskCacheDB::~URLResponseDiskCacheDB() {}
+
+} // namespace mojo

Powered by Google App Engine
This is Rietveld 408576698