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 base::RefCounted<ServiceWorkerDiskCacheMigrator::Task> { | |
|
kinuko
2015/05/27 05:45:14
nit: It's not obvious why this needs to be ref-cou
nhiroki
2015/05/27 10:05:27
I thought the owner of the disk_cache::Entry* shou
| |
| 20 public: | |
| 21 explicit Task(const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner); | |
| 22 | |
| 23 void Run(int task_id, | |
| 24 ServiceWorkerDiskCache* src, | |
| 25 ServiceWorkerDiskCache* dest); | |
| 26 void Abort(); | |
| 27 | |
| 28 private: | |
| 29 friend class base::RefCounted<ServiceWorkerDiskCacheMigrator::Task>; | |
| 30 friend class ServiceWorkerDiskCacheMigrator; | |
|
kinuko
2015/05/27 05:45:14
nit: having this Migrator class friend seems to im
nhiroki
2015/05/27 10:05:27
These 'friend' are no longer necessary. Removed.
| |
| 31 | |
| 32 ~Task(); | |
| 33 | |
| 34 void ReadResponseInfo(); | |
| 35 void OnReadResponseInfo( | |
| 36 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 37 int result); | |
| 38 void OnWriteResponseInfo( | |
| 39 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 40 int result); | |
| 41 void WriteResponseMetadata( | |
| 42 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer); | |
| 43 void OnWriteResponseMetadata(int result); | |
| 44 void ReadResponseData(); | |
| 45 void OnReadResponseData(const scoped_refptr<net::IOBuffer>& buffer, | |
| 46 int result); | |
| 47 void OnWriteResponseData(int result); | |
| 48 void DeleteResponse(); | |
| 49 void OnDeleteResponse(int result); | |
| 50 void Finish(ServiceWorkerStatusCode status); | |
| 51 | |
| 52 IDMap<Task>::KeyType task_id_; | |
| 53 int64 resource_id_ = kInvalidServiceWorkerResourceId; | |
| 54 bool is_aborted_ = false; | |
| 55 | |
| 56 base::WeakPtr<ServiceWorkerDiskCacheMigrator> owner_; | |
| 57 ServiceWorkerDiskCache* src_ = nullptr; | |
| 58 disk_cache::Entry* entry_ = nullptr; | |
| 59 | |
| 60 scoped_ptr<ServiceWorkerResponseReader> reader_; | |
| 61 scoped_ptr<ServiceWorkerResponseWriter> writer_; | |
| 62 scoped_ptr<ServiceWorkerResponseMetadataWriter> metadata_writer_; | |
| 63 | |
| 64 DISALLOW_COPY_AND_ASSIGN(Task); | |
| 65 }; | |
| 66 | |
| 67 ServiceWorkerDiskCacheMigrator::Task::Task( | |
| 68 const base::WeakPtr<ServiceWorkerDiskCacheMigrator>& owner) | |
| 69 : owner_(owner) { | |
| 70 } | |
| 71 | |
| 72 ServiceWorkerDiskCacheMigrator::Task::~Task() { | |
| 73 if (entry_) | |
| 74 entry_->Close(); | |
| 75 } | |
| 76 | |
| 77 void ServiceWorkerDiskCacheMigrator::Task::Run(IDMap<Task>::KeyType task_id, | |
| 78 ServiceWorkerDiskCache* src, | |
| 79 ServiceWorkerDiskCache* dest) { | |
| 80 task_id_ = task_id; | |
| 81 src_ = src; | |
| 82 | |
| 83 DCHECK(entry_); | |
| 84 if (!base::StringToInt64(entry_->GetKey(), &resource_id_)) { | |
| 85 LOG(ERROR) << "Failed to read the resource id"; | |
| 86 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 87 return; | |
| 88 } | |
| 89 DCHECK_NE(kInvalidServiceWorkerResourceId, resource_id_); | |
| 90 | |
| 91 reader_.reset(new ServiceWorkerResponseReader(resource_id_, src)); | |
| 92 writer_.reset(new ServiceWorkerResponseWriter(resource_id_, dest)); | |
| 93 metadata_writer_.reset( | |
| 94 new ServiceWorkerResponseMetadataWriter(resource_id_, dest)); | |
| 95 | |
| 96 ReadResponseInfo(); | |
| 97 } | |
| 98 | |
| 99 void ServiceWorkerDiskCacheMigrator::Task::Abort() { | |
| 100 is_aborted_ = true; | |
| 101 } | |
| 102 | |
| 103 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseInfo() { | |
| 104 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer( | |
| 105 new HttpResponseInfoIOBuffer); | |
| 106 reader_->ReadInfo(info_buffer.get(), | |
| 107 base::Bind(&Task::OnReadResponseInfo, this, info_buffer)); | |
| 108 } | |
| 109 | |
| 110 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseInfo( | |
| 111 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer, | |
| 112 int result) { | |
| 113 if (is_aborted_) | |
| 114 return; | |
| 115 if (result < 0) { | |
| 116 LOG(ERROR) << "Failed to read the response info"; | |
| 117 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 118 return; | |
| 119 } | |
| 120 writer_->WriteInfo(info_buffer.get(), | |
| 121 base::Bind(&Task::OnWriteResponseInfo, this, info_buffer)); | |
| 122 } | |
| 123 | |
| 124 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseInfo( | |
| 125 const scoped_refptr<HttpResponseInfoIOBuffer>& buffer, | |
| 126 int result) { | |
| 127 if (is_aborted_) | |
| 128 return; | |
| 129 if (result < 0) { | |
| 130 LOG(ERROR) << "Failed to write the response info"; | |
| 131 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 132 return; | |
| 133 } | |
| 134 | |
| 135 const net::HttpResponseInfo* http_info = buffer->http_info.get(); | |
| 136 if (http_info->metadata) { | |
| 137 WriteResponseMetadata(buffer); | |
| 138 return; | |
| 139 } | |
| 140 ReadResponseData(); | |
| 141 } | |
| 142 | |
| 143 void ServiceWorkerDiskCacheMigrator::Task::WriteResponseMetadata( | |
| 144 const scoped_refptr<HttpResponseInfoIOBuffer>& info_buffer) { | |
| 145 const net::HttpResponseInfo* http_info = info_buffer->http_info.get(); | |
| 146 const int data_size = http_info->metadata->size(); | |
| 147 | |
| 148 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size); | |
| 149 if (data_size) | |
| 150 memmove(buffer->data(), http_info->metadata->data(), data_size); | |
| 151 metadata_writer_->WriteMetadata( | |
| 152 buffer.get(), data_size, | |
| 153 base::Bind(&Task::OnWriteResponseMetadata, this)); | |
| 154 } | |
| 155 | |
| 156 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseMetadata(int result) { | |
| 157 if (is_aborted_) | |
| 158 return; | |
| 159 if (result < 0) { | |
| 160 LOG(ERROR) << "Failed to write the response metadata"; | |
| 161 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 162 return; | |
| 163 } | |
| 164 ReadResponseData(); | |
| 165 } | |
| 166 | |
| 167 void ServiceWorkerDiskCacheMigrator::Task::ReadResponseData() { | |
| 168 scoped_refptr<net::IOBuffer> buffer = | |
| 169 new net::IOBuffer(entry_->GetDataSize(0)); | |
| 170 reader_->ReadData(buffer.get(), entry_->GetDataSize(0), | |
| 171 base::Bind(&Task::OnReadResponseData, this, buffer)); | |
| 172 } | |
| 173 | |
| 174 void ServiceWorkerDiskCacheMigrator::Task::OnReadResponseData( | |
| 175 const scoped_refptr<net::IOBuffer>& buffer, | |
| 176 int result) { | |
| 177 if (is_aborted_) | |
| 178 return; | |
| 179 if (result < 0) { | |
| 180 LOG(ERROR) << "Failed to read the response data"; | |
| 181 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 182 return; | |
| 183 } | |
| 184 writer_->WriteData(buffer.get(), result, | |
| 185 base::Bind(&Task::OnWriteResponseData, this)); | |
| 186 } | |
| 187 | |
| 188 void ServiceWorkerDiskCacheMigrator::Task::OnWriteResponseData(int result) { | |
| 189 if (is_aborted_) | |
| 190 return; | |
| 191 if (result < 0) { | |
| 192 LOG(ERROR) << "Failed to write the response data"; | |
| 193 Finish(SERVICE_WORKER_ERROR_FAILED); | |
| 194 return; | |
| 195 } | |
| 196 DeleteResponse(); | |
| 197 } | |
| 198 | |
| 199 void ServiceWorkerDiskCacheMigrator::Task::DeleteResponse() { | |
| 200 // Delete the response from the src diskcache so that we can avoid migrating | |
| 201 // it twice when remaining tasks are cancelled due to the storage shutdown and | |
| 202 // a retry happens. | |
|
kinuko
2015/05/27 05:45:15
Do we really want to delete entry one by one while
nhiroki
2015/05/27 10:05:27
Right, half-migrated resources or migrated-but-not
| |
| 203 int result = | |
| 204 src_->DoomEntry(resource_id_, base::Bind(&Task::OnDeleteResponse, this)); | |
| 205 if (result == net::ERR_IO_PENDING) | |
| 206 return; | |
| 207 OnDeleteResponse(result); | |
| 208 } | |
| 209 | |
| 210 void ServiceWorkerDiskCacheMigrator::Task::OnDeleteResponse(int result) { | |
| 211 if (is_aborted_) | |
| 212 return; | |
| 213 if (result < 0) { | |
| 214 LOG(ERROR) << "Failed to delete the response"; | |
| 215 // Ignore an error and try to continue migrating. A leftover response will | |
| 216 // be deleted with the diskcache directory when all tasks are completed. | |
| 217 } | |
| 218 Finish(SERVICE_WORKER_OK); | |
| 219 } | |
| 220 | |
| 221 void ServiceWorkerDiskCacheMigrator::Task::Finish( | |
| 222 ServiceWorkerStatusCode status) { | |
| 223 if (owner_) | |
| 224 owner_->OnResourceMigrated(task_id_, status); | |
| 225 } | |
| 226 | |
| 227 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator( | |
| 228 ServiceWorkerDiskCache* src, | |
| 229 ServiceWorkerDiskCache* dest, | |
| 230 const StatusCallback& callback) | |
| 231 : src_(src), dest_(dest), callback_(callback), weak_factory_(this) { | |
| 232 DCHECK(!src_->is_disabled()); | |
| 233 DCHECK(!dest_->is_disabled()); | |
| 234 } | |
| 235 | |
| 236 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() { | |
| 237 } | |
| 238 | |
| 239 void ServiceWorkerDiskCacheMigrator::Start() { | |
| 240 iterator_ = src_->disk_cache()->CreateIterator(); | |
| 241 ContinueMigratingResources(); | |
| 242 } | |
| 243 | |
| 244 void ServiceWorkerDiskCacheMigrator::ContinueMigratingResources() { | |
| 245 scoped_refptr<Task> next_task(new Task(weak_factory_.GetWeakPtr())); | |
|
kinuko
2015/05/27 05:45:15
Instead of doing this here and initializing necess
nhiroki
2015/05/27 10:05:27
Done.
| |
| 246 | |
| 247 int result = iterator_->OpenNextEntry( | |
| 248 &next_task->entry_, | |
| 249 base::Bind(&ServiceWorkerDiskCacheMigrator::OnOpenNextEntry, | |
| 250 weak_factory_.GetWeakPtr(), next_task)); | |
| 251 if (result == net::ERR_IO_PENDING) | |
| 252 return; | |
| 253 OnOpenNextEntry(next_task, result); | |
| 254 } | |
| 255 | |
| 256 void ServiceWorkerDiskCacheMigrator::OnOpenNextEntry( | |
| 257 const scoped_refptr<Task>& next_task, | |
| 258 int result) { | |
| 259 if (result == net::ERR_FAILED) { | |
| 260 // ERR_FAILED means the iterator reaches the end of the enumeration. | |
| 261 if (inflight_tasks_.IsEmpty()) | |
| 262 callback_.Run(SERVICE_WORKER_OK); | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 if (result != net::OK) { | |
| 267 LOG(ERROR) << "Failed to open the next entry"; | |
| 268 callback_.Run(SERVICE_WORKER_ERROR_FAILED); | |
| 269 return; | |
| 270 } | |
| 271 | |
| 272 IDMap<Task>::KeyType task_id = inflight_tasks_.Add(next_task.get()); | |
| 273 next_task->Run(task_id, src_, dest_); | |
| 274 | |
| 275 ContinueMigratingResources(); | |
| 276 } | |
| 277 | |
| 278 void ServiceWorkerDiskCacheMigrator::OnResourceMigrated( | |
| 279 IDMap<Task>::KeyType task_id, | |
| 280 ServiceWorkerStatusCode status) { | |
| 281 DCHECK(inflight_tasks_.Lookup(task_id)); | |
| 282 inflight_tasks_.Remove(task_id); | |
| 283 | |
| 284 if (status != SERVICE_WORKER_OK) { | |
| 285 AbortAllTasks(); | |
| 286 callback_.Run(status); | |
| 287 return; | |
| 288 } | |
| 289 | |
| 290 if (inflight_tasks_.IsEmpty()) { | |
| 291 callback_.Run(SERVICE_WORKER_OK); | |
| 292 return; | |
| 293 } | |
| 294 | |
| 295 // |callback_| will be invoked when all inflight tasks are completed. | |
| 296 } | |
| 297 | |
| 298 void ServiceWorkerDiskCacheMigrator::AbortAllTasks() { | |
| 299 for (IDMap<Task>::iterator it(&inflight_tasks_); !it.IsAtEnd(); | |
| 300 it.Advance()) { | |
| 301 Task* task = it.GetCurrentValue(); | |
| 302 DCHECK(task); | |
| 303 task->Abort(); | |
| 304 } | |
| 305 inflight_tasks_.Clear(); | |
| 306 } | |
| 307 | |
| 308 } // namespace content | |
| OLD | NEW |