Chromium Code Reviews| 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 "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 // A task to move a cached resource from the src DiskCache to the dest | |
| 17 // DiskCache. This is owned by ServiceWorkerDiskCacheMigrator. | |
| 18 class ServiceWorkerDiskCacheMigrator::Task { | |
| 19 public: | |
| 20 Task(InflightTaskMap::KeyType task_id, | |
| 21 int64 resource_id, | |
| 22 disk_cache::Entry* entry, | |
| 23 ServiceWorkerDiskCache* src, | |
| 24 ServiceWorkerDiskCache* dest, | |
| 25 const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner); | |
| 26 ~Task(); | |
| 27 | |
| 28 void Run(); | |
| 29 | |
| 30 private: | |
| 31 void ReadResponseInfo(); | |
| 32 void OnReadResponseInfo( | |
| 33 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 34 int result); | |
| 35 void OnWriteResponseInfo( | |
| 36 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 37 int result); | |
| 38 void WriteResponseMetadata( | |
| 39 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer); | |
| 40 void OnWriteResponseMetadata(int result); | |
| 41 void ReadResponseData(); | |
| 42 void OnReadResponseData(const scoped_refptr<net::IOBuffer>& buffer, | |
| 43 int result); | |
| 44 void OnWriteResponseData(int result); | |
| 45 void Finish(ServiceWorkerStatusCode status); | |
| 46 | |
| 47 InflightTaskMap::KeyType task_id_; | |
| 48 int64 resource_id_; | |
| 49 disk_cache::Entry* entry_; | |
| 50 base::WeakPtr<ServiceWorkerDiskCacheMigrator> owner_; | |
| 51 | |
| 52 scoped_ptr<ServiceWorkerResponseReader> reader_; | |
| 53 scoped_ptr<ServiceWorkerResponseWriter> writer_; | |
| 54 scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer_; | |
| 55 | |
| 56 base::WeakPtrFactory<Task> weak_factory_; | |
| 57 | |
| 58 DISALLOW_COPY_AND_ASSIGN(Task); | |
| 59 }; | |
| 60 | |
| 61 ServiceWorkerDiskCacheMigrator::Task::Task( | |
| 62 InflightTaskMap::KeyType task_id, | |
| 63 int64 resource_id, | |
| 64 disk_cache::Entry* entry, | |
| 65 ServiceWorkerDiskCache* src, | |
| 66 ServiceWorkerDiskCache* dest, | |
| 67 const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner) | |
| 68 : task_id_(task_id), | |
| 69 resource_id_(resource_id), | |
| 70 entry_(entry), | |
| 71 owner_(owner), | |
| 72 weak_factory_(this) { | |
| 73 DCHECK(entry_); | |
| 74 reader_.reset(new ServiceWorkerResponseReader(resource_id, src)); | |
| 75 writer_.reset(new ServiceWorkerResponseWriter(resource_id, dest)); | |
| 76 metadata_writer_.reset( | |
| 77 new ServiceWorkerResponseMetadataWriter(resource_id, dest)); | |
| 78 } | |
| 79 | |
| 80 ServiceWorkerDiskCacheMigrator::Task::~Task() { | |
| 81 entry_->Close(); | |
| 82 } | |
| 83 | |
| 84 void ServiceWorkerDiskCacheMigrator::Task::Run() { | |
| 85 ReadResponseInfo(); | |
| 86 } | |
| 87 | |
| 88 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseInfo() { | |
| 89 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer( | |
| 90 new HttpResponseInfoIOBuffer); | |
| 91 reader_->ReadInfo(info_buffer.get(), | |
| 92 base::Bind(&Task::OnReadResponseInfo, | |
| 93 weak_factory_.GetWeakPtr(), info_buffer)); | |
| 94 } | |
| 95 | |
| 96 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseInfo( | |
| 97 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 98 int result) { | |
| 99 if (result < 0) { | |
| 100 LOG(ERROR) << "Failed to read the response info"; | |
| 101 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 102 return; | |
| 103 } | |
| 104 writer_->WriteInfo(info_buffer.get(), | |
| 105 base::Bind(&Task::OnWriteResponseInfo, | |
| 106 weak_factory_.GetWeakPtr(), info_buffer)); | |
| 107 } | |
| 108 | |
| 109 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseInfo( | |
| 110 const scoped_refptr<HttpResponseInfoIOBuffer>& buffer, | |
| 111 int result) { | |
| 112 if (result < 0) { | |
| 113 LOG(ERROR) << "Failed to write the response info"; | |
| 114 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 115 return; | |
| 116 } | |
| 117 | |
| 118 const net::HttpResponseInfo* http_info = buffer->http_info.get(); | |
| 119 if (http_info->metadata) { | |
| 120 WriteResponseMetadata(buffer); | |
| 121 return; | |
| 122 } | |
| 123 ReadResponseData(); | |
| 124 } | |
| 125 | |
| 126 void ServiceWorkerDiskCacheMigrator::Task::WriteResponseMetadata( | |
| 127 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer) { | |
| 128 const net::HttpResponseInfo* http_info = info_buffer->http_info.get(); | |
| 129 const int data_size = http_info->metadata->size(); | |
| 130 | |
| 131 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size); | |
| 132 if (data_size) | |
| 133 memmove(buffer->data(), http_info->metadata->data(), data_size); | |
|
michaeln
2015/05/27 23:09:23
This copy is unfortunate, i think there's an IOBuf
nhiroki
2015/05/28 07:47:11
I see. I replaced memmove with WrapppedIOBuffer, a
| |
| 134 metadata_writer_->WriteMetadata( | |
| 135 buffer.get(), data_size, | |
| 136 base::Bind(&Task::OnWriteResponseMetadata, weak_factory_.GetWeakPtr())); | |
| 137 } | |
| 138 | |
| 139 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseMetadata(int result) { | |
| 140 if (result < 0) { | |
| 141 LOG(ERROR) << "Failed to write the response metadata"; | |
| 142 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 143 return; | |
| 144 } | |
| 145 ReadResponseData(); | |
| 146 } | |
| 147 | |
| 148 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseData() { | |
| 149 scoped_refptr<net::IOBuffer> buffer = | |
| 150 new net::IOBuffer(entry_->GetDataSize(0)); | |
| 151 reader_->ReadData(buffer.get(), entry_->GetDataSize(0), | |
| 152 base::Bind(&Task::OnReadResponseData, | |
| 153 weak_factory_.GetWeakPtr(), buffer)); | |
| 154 } | |
| 155 | |
| 156 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseData( | |
| 157 const scoped_refptr<net::IOBuffer>& buffer, | |
| 158 int result) { | |
| 159 if (result < 0) { | |
| 160 LOG(ERROR) << "Failed to read the response data"; | |
| 161 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 162 return; | |
| 163 } | |
| 164 writer_->WriteData( | |
| 165 buffer.get(), result, | |
| 166 base::Bind(&Task::OnWriteResponseData, weak_factory_.GetWeakPtr())); | |
| 167 } | |
| 168 | |
| 169 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseData(int result) { | |
| 170 if (result < 0) { | |
| 171 LOG(ERROR) << "Failed to write the response data"; | |
| 172 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 173 return; | |
| 174 } | |
| 175 Finish(SERVICE_WORKER_OK); | |
| 176 } | |
| 177 | |
| 178 void ServiceWorkerDiskCacheMigrator::Task::Finish( | |
| 179 ServiceWorkerStatusCode status) { | |
| 180 DCHECK(owner_); | |
| 181 owner_->OnResourceMigrated(task_id_, status); | |
| 182 } | |
| 183 | |
| 184 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator( | |
| 185 ServiceWorkerDiskCache* src, | |
| 186 ServiceWorkerDiskCache* dest) | |
| 187 : src_(src), dest_(dest), weak_factory_(this) { | |
| 188 DCHECK(!src_->is_disabled()); | |
| 189 DCHECK(!dest_->is_disabled()); | |
| 190 } | |
| 191 | |
| 192 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() { | |
| 193 } | |
| 194 | |
| 195 void ServiceWorkerDiskCacheMigrator::Start(const StatusCallback& callback) { | |
| 196 callback_ = callback; | |
| 197 iterator_ = src_->disk_cache()->CreateIterator(); | |
| 198 ContinueMigratingResources(); | |
| 199 } | |
| 200 | |
| 201 void ServiceWorkerDiskCacheMigrator::ContinueMigratingResources() { | |
| 202 disk_cache::Entry** entry = new disk_cache::Entry*(); | |
| 203 net::CompletionCallback callback = | |
| 204 base::Bind(&ServiceWorkerDiskCacheMigrator::OnOpenNextEntry, | |
| 205 weak_factory_.GetWeakPtr(), base::Owned(entry)); | |
| 206 int result = iterator_->OpenNextEntry(entry, callback); | |
| 207 if (result == net::ERR_IO_PENDING) | |
| 208 return; | |
| 209 callback.Run(result); | |
| 210 } | |
| 211 | |
| 212 void ServiceWorkerDiskCacheMigrator::OnOpenNextEntry(disk_cache::Entry** entry, | |
| 213 int result) { | |
| 214 if (result == net::ERR_FAILED) { | |
| 215 // ERR_FAILED means the iterator reaches the end of the enumeration. | |
| 216 if (inflight_tasks_.IsEmpty()) | |
| 217 Complete(SERVICE_WORKER_OK); | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 if (result != net::OK) { | |
| 222 LOG(ERROR) << "Failed to open the next entry"; | |
| 223 inflight_tasks_.Clear(); | |
| 224 Complete(SERVICE_WORKER_ERROR_FAILED); | |
| 225 return; | |
| 226 } | |
| 227 | |
| 228 int64 resource_id = kInvalidServiceWorkerResourceId; | |
| 229 if (!base::StringToInt64((*entry)->GetKey(), &resource_id)) { | |
|
michaeln
2015/05/27 23:09:23
Does anything call (*entry)->Close() in this case
nhiroki
2015/05/28 07:47:11
Good point. To fix this, I introduced WrappedEntry
| |
| 230 LOG(ERROR) << "Failed to read the resource id"; | |
| 231 inflight_tasks_.Clear(); | |
| 232 Complete(SERVICE_WORKER_ERROR_FAILED); | |
| 233 return; | |
| 234 } | |
| 235 | |
| 236 InflightTaskMap::KeyType task_id = next_task_id_++; | |
| 237 scoped_ptr<Task> next_task(new Task(task_id, resource_id, *entry, src_, dest_, | |
| 238 weak_factory_.GetWeakPtr())); | |
| 239 next_task->Run(); | |
|
michaeln
2015/05/27 23:09:23
Looks like this will create and start tasks to mig
nhiroki
2015/05/28 00:21:09
In the current patchset, there is no mechanism to
nhiroki
2015/05/28 07:47:11
Done.
| |
| 240 inflight_tasks_.AddWithID(next_task.release(), task_id); | |
| 241 | |
| 242 ContinueMigratingResources(); | |
| 243 } | |
| 244 | |
| 245 void ServiceWorkerDiskCacheMigrator::OnResourceMigrated( | |
| 246 InflightTaskMap::KeyType task_id, | |
| 247 ServiceWorkerStatusCode status) { | |
| 248 DCHECK(inflight_tasks_.Lookup(task_id)); | |
| 249 inflight_tasks_.Remove(task_id); | |
| 250 | |
| 251 if (status != SERVICE_WORKER_OK) { | |
| 252 inflight_tasks_.Clear(); | |
| 253 Complete(status); | |
| 254 return; | |
| 255 } | |
| 256 | |
| 257 if (inflight_tasks_.IsEmpty()) { | |
| 258 Complete(SERVICE_WORKER_OK); | |
| 259 return; | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void ServiceWorkerDiskCacheMigrator::Complete(ServiceWorkerStatusCode status) { | |
| 264 DCHECK(inflight_tasks_.IsEmpty()); | |
| 265 // TODO(nhiroki): Add UMA for the result of migration. | |
| 266 callback_.Run(status); | |
| 267 } | |
| 268 | |
| 269 } // namespace content | |
| OLD | NEW |