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

Side by Side Diff: content/browser/service_worker/service_worker_disk_cache_migrator.cc

Issue 1155063002: ServiceWorker: Introduce ServiceWorkerDiskCacheMigrator (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add DCHECKs Created 5 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
OLDNEW
(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 "content/browser/service_worker/service_worker_disk_cache_migrator.h"
6
7 #include "base/memory/ref_counted.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "content/common/service_worker/service_worker_types.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/disk_cache/disk_cache.h"
13
14 namespace content {
15
16 namespace {
17
18 // Disk cache entry data indices (Copied from appcache_diskcache.cc).
19 enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex };
20
21 } // namespace
22
23 // A task to move a cached resource from the src DiskCache to the dest
24 // DiskCache. This is owned by ServiceWorkerDiskCacheMigrator.
25 class ServiceWorkerDiskCacheMigrator::Task {
26 public:
27 Task(InflightTaskMap::KeyType task_id,
28 int64 resource_id,
29 int32 data_size,
30 ServiceWorkerDiskCache* src,
31 ServiceWorkerDiskCache* dest,
32 const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner);
33 ~Task();
34
35 void Run();
36
37 InflightTaskMap::KeyType task_id() const { return task_id_; }
38
39 private:
40 void ReadResponseInfo();
41 void OnReadResponseInfo(
42 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer,
43 int result);
44 void OnWriteResponseInfo(
45 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer,
46 int result);
47 void WriteResponseMetadata(
48 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer);
49 void OnWriteResponseMetadata(
50 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer,
51 int result);
52 void ReadResponseData();
53 void OnReadResponseData(const scoped_refptr<net::IOBuffer>& buffer,
54 int result);
55 void OnWriteResponseData(int result);
56 void Finish(ServiceWorkerStatusCode status);
57
58 InflightTaskMap::KeyType task_id_;
59 int64 resource_id_;
60 int32 data_size_;
61 base::WeakPtr<ServiceWorkerDiskCacheMigrator> owner_;
62
63 scoped_ptr<ServiceWorkerResponseReader> reader_;
64 scoped_ptr<ServiceWorkerResponseWriter> writer_;
65 scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer_;
66
67 base::WeakPtrFactory<Task> weak_factory_;
68
69 DISALLOW_COPY_AND_ASSIGN(Task);
70 };
71
72 // A wrapper class for disk_cache::Entry. This is used for holding an open entry
73 // and ensuring that the entry gets closed on the dtor.
74 class ServiceWorkerDiskCacheMigrator::WrappedEntry {
75 public:
76 WrappedEntry() {}
77
78 ~WrappedEntry() {
79 if (entry_)
80 entry_->Close();
81 }
82
83 disk_cache::Entry* Unwrap() {
84 disk_cache::Entry* entry = entry_;
85 entry_ = nullptr;
86 return entry;
87 }
88
89 disk_cache::Entry** GetPtr() { return &entry_; }
90
91 private:
92 disk_cache::Entry* entry_ = nullptr;
93
94 DISALLOW_COPY_AND_ASSIGN(WrappedEntry);
95 };
96
97 ServiceWorkerDiskCacheMigrator::Task::Task(
98 InflightTaskMap::KeyType task_id,
99 int64 resource_id,
100 int32 data_size,
101 ServiceWorkerDiskCache* src,
102 ServiceWorkerDiskCache* dest,
103 const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner)
104 : task_id_(task_id),
105 resource_id_(resource_id),
106 data_size_(data_size),
107 owner_(owner),
108 weak_factory_(this) {
109 DCHECK_LE(0, data_size_);
110 reader_.reset(new ServiceWorkerResponseReader(resource_id, src));
111 writer_.reset(new ServiceWorkerResponseWriter(resource_id, dest));
112 metadata_writer_.reset(
113 new ServiceWorkerResponseMetadataWriter(resource_id, dest));
114 }
115
116 ServiceWorkerDiskCacheMigrator::Task::~Task() {
117 }
118
119 void ServiceWorkerDiskCacheMigrator::Task::Run() {
120 ReadResponseInfo();
121 }
122
123 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseInfo() {
124 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer(
125 new HttpResponseInfoIOBuffer);
126 reader_->ReadInfo(info_buffer.get(),
127 base::Bind(&Task::OnReadResponseInfo,
128 weak_factory_.GetWeakPtr(), info_buffer));
129 }
130
131 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseInfo(
132 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer,
133 int result) {
134 if (result < 0) {
135 LOG(ERROR) << "Failed to read the response info";
136 Finish(SERVICE_WORKER_ERROR_FAILED);
137 return;
138 }
139 writer_->WriteInfo(info_buffer.get(),
140 base::Bind(&Task::OnWriteResponseInfo,
141 weak_factory_.GetWeakPtr(), info_buffer));
142 }
143
144 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseInfo(
145 const scoped_refptr<HttpResponseInfoIOBuffer>& buffer,
146 int result) {
147 if (result < 0) {
148 LOG(ERROR) << "Failed to write the response info";
149 Finish(SERVICE_WORKER_ERROR_FAILED);
150 return;
151 }
152
153 const net::HttpResponseInfo* http_info = buffer->http_info.get();
154 if (http_info->metadata && http_info->metadata->size()) {
155 WriteResponseMetadata(buffer);
156 return;
157 }
158 ReadResponseData();
159 }
160
161 void ServiceWorkerDiskCacheMigrator::Task::WriteResponseMetadata(
162 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer) {
163 const net::HttpResponseInfo* http_info = info_buffer->http_info.get();
164 DCHECK(http_info->metadata);
165 DCHECK(http_info->metadata->size());
166
167 // |wrapped_buffer| does not own the given metadata buffer, so a callback
168 // for WriteMetadata keeps |info_buffer| which is the real owner of the
169 // metadata buffer.
170 scoped_refptr<net::WrappedIOBuffer> wrapped_buffer =
171 new net::WrappedIOBuffer(http_info->metadata->data());
172 metadata_writer_->WriteMetadata(
173 wrapped_buffer.get(), http_info->metadata->size(),
174 base::Bind(&Task::OnWriteResponseMetadata, weak_factory_.GetWeakPtr(),
175 info_buffer));
176 }
177
178 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseMetadata(
179 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer,
180 int result) {
181 if (result < 0) {
182 LOG(ERROR) << "Failed to write the response metadata";
183 Finish(SERVICE_WORKER_ERROR_FAILED);
184 return;
185 }
186 DCHECK_EQ(info_buffer->http_info->metadata->size(), result);
187 ReadResponseData();
188 }
189
190 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseData() {
191 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size_);
192 reader_->ReadData(buffer.get(), data_size_,
193 base::Bind(&Task::OnReadResponseData,
194 weak_factory_.GetWeakPtr(), buffer));
195 }
196
197 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseData(
198 const scoped_refptr<net::IOBuffer>& buffer,
199 int result) {
200 if (result < 0) {
201 LOG(ERROR) << "Failed to read the response data";
202 Finish(SERVICE_WORKER_ERROR_FAILED);
203 return;
204 }
205 DCHECK_EQ(data_size_, result);
206 writer_->WriteData(
207 buffer.get(), result,
208 base::Bind(&Task::OnWriteResponseData, weak_factory_.GetWeakPtr()));
209 }
210
211 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseData(int result) {
212 if (result < 0) {
213 LOG(ERROR) << "Failed to write the response data";
214 Finish(SERVICE_WORKER_ERROR_FAILED);
215 return;
216 }
217 DCHECK_EQ(data_size_, result);
218 Finish(SERVICE_WORKER_OK);
219 }
220
221 void ServiceWorkerDiskCacheMigrator::Task::Finish(
222 ServiceWorkerStatusCode status) {
223 DCHECK(owner_);
224 owner_->OnEntryMigrated(task_id_, status);
225 }
226
227 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator(
228 ServiceWorkerDiskCache* src,
229 ServiceWorkerDiskCache* dest)
230 : src_(src), dest_(dest), weak_factory_(this) {
231 DCHECK(!src_->is_disabled());
232 DCHECK(!dest_->is_disabled());
233 }
234
235 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() {
236 }
237
238 void ServiceWorkerDiskCacheMigrator::Start(const StatusCallback& callback) {
239 callback_ = callback;
240 iterator_ = src_->disk_cache()->CreateIterator();
241 OpenNextEntry();
242 }
243
244 void ServiceWorkerDiskCacheMigrator::OpenNextEntry() {
245 DCHECK(!pending_task_);
246 DCHECK(!is_iterating_);
247 is_iterating_ = true;
248
249 scoped_ptr<WrappedEntry> wrapped_entry(new WrappedEntry);
250 disk_cache::Entry** entry_ptr = wrapped_entry->GetPtr();
251
252 net::CompletionCallback callback = base::Bind(
253 &ServiceWorkerDiskCacheMigrator::OnNextEntryOpened,
254 weak_factory_.GetWeakPtr(), base::Passed(wrapped_entry.Pass()));
255 int result = iterator_->OpenNextEntry(entry_ptr, callback);
256 if (result == net::ERR_IO_PENDING)
257 return;
258 callback.Run(result);
259 }
260
261 void ServiceWorkerDiskCacheMigrator::OnNextEntryOpened(
262 scoped_ptr<WrappedEntry> wrapped_entry,
263 int result) {
264 DCHECK(!pending_task_);
265 is_iterating_ = false;
266
267 if (result == net::ERR_FAILED) {
268 // ERR_FAILED means the iterator reached the end of the enumeration.
269 if (inflight_tasks_.IsEmpty())
270 Complete(SERVICE_WORKER_OK);
271 return;
272 }
273
274 if (result != net::OK) {
275 LOG(ERROR) << "Failed to open the next entry";
276 inflight_tasks_.Clear();
277 Complete(SERVICE_WORKER_ERROR_FAILED);
278 return;
279 }
280
281 disk_cache::ScopedEntryPtr scoped_entry(wrapped_entry->Unwrap());
282 DCHECK(scoped_entry);
283
284 int64 resource_id = kInvalidServiceWorkerResourceId;
285 if (!base::StringToInt64(scoped_entry->GetKey(), &resource_id)) {
286 LOG(ERROR) << "Failed to read the resource id";
287 inflight_tasks_.Clear();
288 Complete(SERVICE_WORKER_ERROR_FAILED);
289 return;
290 }
291
292 InflightTaskMap::KeyType task_id = next_task_id_++;
293 pending_task_.reset(new Task(task_id, resource_id,
294 scoped_entry->GetDataSize(kResponseContentIndex),
295 src_, dest_, weak_factory_.GetWeakPtr()));
296 if (inflight_tasks_.size() < max_number_of_inflight_tasks_) {
297 RunPendingTask();
298 OpenNextEntry();
299 return;
300 }
301 // |pending_task_| will run when an inflight task is completed.
302 }
303
304 void ServiceWorkerDiskCacheMigrator::RunPendingTask() {
305 DCHECK(pending_task_);
306 DCHECK_GT(max_number_of_inflight_tasks_, inflight_tasks_.size());
307 InflightTaskMap::KeyType task_id = pending_task_->task_id();
308 pending_task_->Run();
309 inflight_tasks_.AddWithID(pending_task_.release(), task_id);
310 }
311
312 void ServiceWorkerDiskCacheMigrator::OnEntryMigrated(
313 InflightTaskMap::KeyType task_id,
314 ServiceWorkerStatusCode status) {
315 DCHECK(inflight_tasks_.Lookup(task_id));
316 inflight_tasks_.Remove(task_id);
317
318 if (status != SERVICE_WORKER_OK) {
319 inflight_tasks_.Clear();
320 Complete(status);
321 return;
322 }
323
324 if (pending_task_) {
325 RunPendingTask();
326 OpenNextEntry();
327 return;
328 }
329
330 if (is_iterating_)
331 return;
332
333 if (inflight_tasks_.IsEmpty())
334 Complete(SERVICE_WORKER_OK);
335 }
336
337 void ServiceWorkerDiskCacheMigrator::Complete(ServiceWorkerStatusCode status) {
338 DCHECK(inflight_tasks_.IsEmpty());
339 // TODO(nhiroki): Add UMA for the result of migration.
340 callback_.Run(status);
341 }
342
343 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698