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

Side by Side Diff: chromeos/printing/ppd_cache.cc

Issue 2939373003: Convert PpdCache and PpdProvider to TaskScheduler. (Closed)
Patch Set: rebase Created 3 years, 6 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 unified diff | Download patch
« no previous file with comments | « chromeos/printing/ppd_cache.h ('k') | chromeos/printing/ppd_cache_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromeos/printing/ppd_cache.h" 5 #include "chromeos/printing/ppd_cache.h"
6 6
7 #include <utility> 7 #include <utility>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
12 #include "base/json/json_parser.h" 12 #include "base/json/json_parser.h"
13 #include "base/json/json_writer.h" 13 #include "base/json/json_writer.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
17 #include "base/synchronization/lock.h" 17 #include "base/synchronization/lock.h"
18 #include "base/task_runner_util.h"
19 #include "base/task_scheduler/post_task.h"
18 #include "base/threading/sequenced_task_runner_handle.h" 20 #include "base/threading/sequenced_task_runner_handle.h"
19 #include "base/threading/thread_restrictions.h" 21 #include "base/threading/thread_restrictions.h"
20 #include "base/time/time.h" 22 #include "base/time/time.h"
21 #include "base/values.h" 23 #include "base/values.h"
22 #include "chromeos/printing/printing_constants.h" 24 #include "chromeos/printing/printing_constants.h"
23 #include "crypto/sha2.h" 25 #include "crypto/sha2.h"
24 #include "net/base/io_buffer.h" 26 #include "net/base/io_buffer.h"
25 #include "net/filter/gzip_header.h" 27 #include "net/filter/gzip_header.h"
26 28
27 namespace chromeos { 29 namespace chromeos {
28 namespace printing { 30 namespace printing {
29 namespace { 31 namespace {
30 32
33 // Return the (full) path to the file we expect to find the given key at.
34 base::FilePath FilePathForKey(const base::FilePath& base_dir,
35 const std::string& key) {
36 std::string hashed_key = crypto::SHA256HashString(key);
37 return base_dir.Append(base::HexEncode(hashed_key.data(), hashed_key.size()));
38 }
39
40 // If the cache doesn't already exist, create it.
41 void MaybeCreateCache(const base::FilePath& base_dir) {
42 if (!base::PathExists(base_dir)) {
43 base::CreateDirectory(base_dir);
44 }
45 }
46
47 // Find implementation, blocks on file access. Must be run on a thread that
48 // allows I/O.
49 PpdCache::FindResult FindImpl(const base::FilePath& cache_dir,
50 const std::string& key) {
51 base::ThreadRestrictions::AssertIOAllowed();
52
53 PpdCache::FindResult result;
54 result.success = false;
55 MaybeCreateCache(cache_dir);
Carlson 2017/06/20 18:57:33 This patch makes lookups higher priorities than st
skau 2017/06/20 20:23:09 That's a good idea!
56 base::File file(FilePathForKey(cache_dir, key),
57 base::File::FLAG_OPEN | base::File::FLAG_READ);
58
59 if (file.IsValid()) {
60 int64_t len = file.GetLength();
61 if (len >= static_cast<int64_t>(crypto::kSHA256Length) &&
62 len <= static_cast<int64_t>(kMaxPpdSizeBytes) +
63 static_cast<int64_t>(crypto::kSHA256Length)) {
64 std::unique_ptr<char[]> buf(new char[len]);
65 if (file.ReadAtCurrentPos(buf.get(), len) == len) {
gab 2017/06/20 20:36:07 This allows concurrent read/writes to the same fil
66 base::StringPiece contents(buf.get(), len - crypto::kSHA256Length);
67 base::StringPiece checksum(buf.get() + len - crypto::kSHA256Length,
68 crypto::kSHA256Length);
69 if (crypto::SHA256HashString(contents) == checksum) {
70 base::File::Info info;
71 if (file.GetInfo(&info)) {
72 result.success = true;
73 result.age = base::Time::Now() - info.last_modified;
74 contents.CopyToString(&result.contents);
75 }
76 } else {
77 LOG(ERROR) << "Bad checksum for cache key " << key;
78 }
79 }
80 }
81 }
82
83 return result;
84 }
85
86 // Store implementation, blocks on file access. Must be run on a thread that
87 // allows I/O.
88 void StoreImpl(const base::FilePath& cache_dir,
89 const std::string& key,
90 const std::string& contents) {
91 base::ThreadRestrictions::AssertIOAllowed();
92
93 MaybeCreateCache(cache_dir);
94 if (contents.size() > kMaxPpdSizeBytes) {
95 LOG(ERROR) << "Ignoring attempt to cache large object";
96 } else {
97 auto path = FilePathForKey(cache_dir, key);
98 base::File file(path,
99 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
100 std::string checksum = crypto::SHA256HashString(contents);
101 if (!file.IsValid() ||
102 file.WriteAtCurrentPos(contents.data(), contents.size()) !=
103 static_cast<int>(contents.size()) ||
104 file.WriteAtCurrentPos(checksum.data(), checksum.size()) !=
105 static_cast<int>(checksum.size())) {
106 LOG(ERROR) << "Failed to create ppd cache file";
107 file.Close();
108 if (!base::DeleteFile(path, false)) {
109 LOG(ERROR) << "Failed to cleanup failed creation.";
110 }
111 }
112 }
113 }
114
31 class PpdCacheImpl : public PpdCache { 115 class PpdCacheImpl : public PpdCache {
32 public: 116 public:
33 PpdCacheImpl(const base::FilePath& cache_base_dir, 117 explicit PpdCacheImpl(const base::FilePath& cache_base_dir)
34 const scoped_refptr<base::SequencedTaskRunner>& disk_task_runner) 118 : cache_base_dir_(cache_base_dir),
35 : cache_base_dir_(cache_base_dir), disk_task_runner_(disk_task_runner) {} 119 fetch_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
120 {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
121 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
122 store_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
123 {base::TaskPriority::BACKGROUND, base::MayBlock(),
124 base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) {}
36 125
37 // Public API functions. 126 // Public API functions.
38 void Find(const std::string& key, const FindCallback& cb) override { 127 void Find(const std::string& key, const FindCallback& cb) override {
39 // Ensure the cache lives until the op is over. 128 base::PostTaskAndReplyWithResult(
40 AddRef(); 129 fetch_task_runner_.get(), FROM_HERE,
41 ++inflight_ops_; 130 base::Bind(&FindImpl, cache_base_dir_, key), cb);
42 disk_task_runner_->PostTask(
43 FROM_HERE, base::Bind(&PpdCacheImpl::FindImpl, this, key,
44 base::SequencedTaskRunnerHandle::Get(), cb));
45 } 131 }
46 132
47 // Store the given contents at the given key. If cb is non-null, it will 133 // Store the given contents at the given key. If cb is non-null, it will
48 // be invoked on completion. 134 // be invoked on completion.
49 void Store(const std::string& key, 135 void Store(const std::string& key,
50 const std::string& contents, 136 const std::string& contents,
51 const base::Callback<void()>& cb) override { 137 const base::Closure& cb) override {
52 AddRef(); 138 store_task_runner_->PostTaskAndReply(
53 ++inflight_ops_; 139 FROM_HERE, base::Bind(&StoreImpl, cache_base_dir_, key, contents), cb);
54 disk_task_runner_->PostTask(
55 FROM_HERE, base::Bind(&PpdCacheImpl::StoreImpl, this, key, contents,
56 base::SequencedTaskRunnerHandle::Get(), cb));
57 } 140 }
58 141
59 bool Idle() const override { return inflight_ops_ == 0; }
60
61 private: 142 private:
62 ~PpdCacheImpl() override {} 143 ~PpdCacheImpl() override {}
63 144
64 // If the cache doesn't already exist, create it.
65 void MaybeCreateCache() {
66 if (!base::PathExists(cache_base_dir_)) {
67 base::CreateDirectory(cache_base_dir_);
68 }
69 }
70
71 // Find implementation, runs on the i/o thread.
72 void FindImpl(const std::string& key,
73 const scoped_refptr<base::SequencedTaskRunner>& callback_runner,
74 const FindCallback& cb) {
75 base::ThreadRestrictions::AssertIOAllowed();
76 FindResult result;
77 result.success = false;
78 MaybeCreateCache();
79 base::File file(FilePathForKey(key),
80 base::File::FLAG_OPEN | base::File::FLAG_READ);
81
82 if (file.IsValid()) {
83 int64_t len = file.GetLength();
84 if (len >= static_cast<int64_t>(crypto::kSHA256Length) &&
85 len <= static_cast<int64_t>(kMaxPpdSizeBytes) +
86 static_cast<int64_t>(crypto::kSHA256Length)) {
87 std::unique_ptr<char[]> buf(new char[len]);
88 if (file.ReadAtCurrentPos(buf.get(), len) == len) {
89 base::StringPiece contents(buf.get(), len - crypto::kSHA256Length);
90 base::StringPiece checksum(buf.get() + len - crypto::kSHA256Length,
91 crypto::kSHA256Length);
92 if (crypto::SHA256HashString(contents) == checksum) {
93 base::File::Info info;
94 if (file.GetInfo(&info)) {
95 result.success = true;
96 result.age = base::Time::Now() - info.last_modified;
97 contents.CopyToString(&result.contents);
98 }
99 } else {
100 LOG(ERROR) << "Bad checksum for cache key " << key;
101 }
102 }
103 }
104 }
105 callback_runner->PostTask(FROM_HERE,
106 base::Bind(&PpdCacheImpl::ReplyAndRelease, this,
107 base::Bind(cb, result)));
108 }
109
110 // If |cb| is non-null, invoke it on this thread, then decrement the refcount.
111 void ReplyAndRelease(const base::Callback<void()>& cb) {
112 if (!cb.is_null()) {
113 cb.Run();
114 }
115 --inflight_ops_;
116 Release();
117 // Object may be destroyed here, so no further access to object data
118 // allowed.
119 }
120
121 // Store implementation, runs on the i/o thread.
122 void StoreImpl(
123 const std::string& key,
124 const std::string& contents,
125 const scoped_refptr<base::SequencedTaskRunner>& callback_runner,
126 const base::Callback<void()> cb) {
127 base::ThreadRestrictions::AssertIOAllowed();
128 MaybeCreateCache();
129 if (contents.size() > kMaxPpdSizeBytes) {
130 LOG(ERROR) << "Ignoring attempt to cache large object";
131 } else {
132 auto path = FilePathForKey(key);
133 base::File file(path,
134 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
135 std::string checksum = crypto::SHA256HashString(contents);
136 if (!file.IsValid() ||
137 file.WriteAtCurrentPos(contents.data(), contents.size()) !=
138 static_cast<int>(contents.size()) ||
139 file.WriteAtCurrentPos(checksum.data(), checksum.size()) !=
140 static_cast<int>(checksum.size())) {
141 LOG(ERROR) << "Failed to create ppd cache file";
142 file.Close();
143 if (!base::DeleteFile(path, false)) {
144 LOG(ERROR) << "Failed to cleanup failed creation.";
145 }
146 }
147 }
148 callback_runner->PostTask(
149 FROM_HERE, base::Bind(&PpdCacheImpl::ReplyAndRelease, this, cb));
150 }
151
152 // Return the (full) path to the file we expect to find the given key at.
153 base::FilePath FilePathForKey(const std::string& key) {
154 std::string hashed_key = crypto::SHA256HashString(key);
155 return cache_base_dir_.Append(
156 base::HexEncode(hashed_key.data(), hashed_key.size()));
157 }
158
159 int inflight_ops_ = 0;
160
161 base::FilePath cache_base_dir_; 145 base::FilePath cache_base_dir_;
162 scoped_refptr<base::SequencedTaskRunner> disk_task_runner_; 146 scoped_refptr<base::SequencedTaskRunner> fetch_task_runner_;
147 scoped_refptr<base::SequencedTaskRunner> store_task_runner_;
163 148
164 DISALLOW_COPY_AND_ASSIGN(PpdCacheImpl); 149 DISALLOW_COPY_AND_ASSIGN(PpdCacheImpl);
165 }; 150 };
166 151
167 } // namespace 152 } // namespace
168 153
169 // static 154 // static
170 scoped_refptr<PpdCache> PpdCache::Create( 155 scoped_refptr<PpdCache> PpdCache::Create(const base::FilePath& cache_base_dir) {
171 const base::FilePath& cache_base_dir, 156 return scoped_refptr<PpdCache>(new PpdCacheImpl(cache_base_dir));
172 scoped_refptr<base::SequencedTaskRunner> disk_task_runner) {
173 return scoped_refptr<PpdCache>(
174 new PpdCacheImpl(cache_base_dir, disk_task_runner));
175 } 157 }
176 158
177 } // namespace printing 159 } // namespace printing
178 } // namespace chromeos 160 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/printing/ppd_cache.h ('k') | chromeos/printing/ppd_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698