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

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_uploader.cc

Issue 10540132: gdata: Convert GDataFileSystem::AddUploadFile() to asynchronous. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Satoru's comments. Created 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/chromeos/gdata/gdata_uploader.h" 5 #include "chrome/browser/chromeos/gdata/gdata_uploader.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 int GDataUploader::UploadFile(scoped_ptr<UploadFileInfo> upload_file_info) { 45 int GDataUploader::UploadFile(scoped_ptr<UploadFileInfo> upload_file_info) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
47 DCHECK(upload_file_info.get()); 47 DCHECK(upload_file_info.get());
48 DCHECK_EQ(upload_file_info->upload_id, -1); 48 DCHECK_EQ(upload_file_info->upload_id, -1);
49 DCHECK(!upload_file_info->file_path.empty()); 49 DCHECK(!upload_file_info->file_path.empty());
50 DCHECK_NE(upload_file_info->file_size, 0); 50 DCHECK_NE(upload_file_info->file_size, 0);
51 DCHECK(!upload_file_info->gdata_path.empty()); 51 DCHECK(!upload_file_info->gdata_path.empty());
52 DCHECK(!upload_file_info->title.empty()); 52 DCHECK(!upload_file_info->title.empty());
53 DCHECK(!upload_file_info->content_type.empty()); 53 DCHECK(!upload_file_info->content_type.empty());
54 54
55 base::AutoLock lock(lock_);
56
55 const int upload_id = next_upload_id_++; 57 const int upload_id = next_upload_id_++;
56 upload_file_info->upload_id = upload_id; 58 upload_file_info->upload_id = upload_id;
57 // Add upload_file_info to our internal map and take ownership. 59 // Add upload_file_info to our internal map and take ownership.
58 pending_uploads_[upload_id] = upload_file_info.release(); 60 pending_uploads_[upload_id] = upload_file_info.release();
59 61
60 UploadFileInfo* info = GetUploadFileInfo(upload_id); 62 UploadFileInfo* info = GetUploadFileInfo(upload_id);
61 DVLOG(1) << "Uploading file: " << info->DebugString(); 63 DVLOG(1) << "Uploading file: " << info->DebugString();
62 64
63 // Create a FileStream to make sure the file can be opened successfully. 65 // Create a FileStream to make sure the file can be opened successfully.
64 info->file_stream = new net::FileStream(NULL); 66 info->file_stream = new net::FileStream(NULL);
65 67
66 // Create buffer to hold upload data. 68 // Create buffer to hold upload data.
67 info->buf_len = std::min(info->file_size, kUploadChunkSize); 69 info->buf_len = std::min(info->file_size, kUploadChunkSize);
68 info->buf = new net::IOBuffer(info->buf_len); 70 info->buf = new net::IOBuffer(info->buf_len);
69 71
70 OpenFile(info); 72 OpenFile(info);
71 return upload_id; 73 return upload_id;
72 } 74 }
73 75
74 void GDataUploader::UpdateUpload(int upload_id, 76 void GDataUploader::UpdateUpload(int upload_id,
75 content::DownloadItem* download) { 77 content::DownloadItem* download) {
satorux1 2012/06/14 21:32:34 on what thread is this function called? In other p
hshi1 2012/06/14 21:40:17 Done.
satorux1 2012/06/14 21:47:25 Hmm, then seems to me that all functions run on UI
78 base::AutoLock lock(lock_);
79
76 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); 80 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id);
77 if (!upload_file_info) 81 if (!upload_file_info)
78 return; 82 return;
79 83
80 const int64 file_size = download->GetReceivedBytes(); 84 const int64 file_size = download->GetReceivedBytes();
81 85
82 // Update file_size and all_bytes_present. 86 // Update file_size and all_bytes_present.
83 DVLOG(1) << "Updating file size from " << upload_file_info->file_size 87 DVLOG(1) << "Updating file size from " << upload_file_info->file_size
84 << " to " << file_size 88 << " to " << file_size
85 << (download->AllDataSaved() ? " (AllDataSaved)" : " (In-progress)"); 89 << (download->AllDataSaved() ? " (AllDataSaved)" : " (In-progress)");
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 UploadFileInfo* upload_info = GetUploadFileInfo(upload_id); 131 UploadFileInfo* upload_info = GetUploadFileInfo(upload_id);
128 // We return the start_range as the count of uploaded bytes since that is the 132 // We return the start_range as the count of uploaded bytes since that is the
129 // start of the next or currently uploading chunk. 133 // start of the next or currently uploading chunk.
130 // TODO(asanka): Use a finer grained progress value than this. We end up 134 // TODO(asanka): Use a finer grained progress value than this. We end up
131 // reporting progress in kUploadChunkSize increments. 135 // reporting progress in kUploadChunkSize increments.
132 return upload_info ? upload_info->start_range : 0; 136 return upload_info ? upload_info->start_range : 0;
133 } 137 }
134 138
135 UploadFileInfo* GDataUploader::GetUploadFileInfo(int upload_id) const { 139 UploadFileInfo* GDataUploader::GetUploadFileInfo(int upload_id) const {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141 lock_.AssertAcquired();
137 142
138 UploadFileInfoMap::const_iterator it = pending_uploads_.find(upload_id); 143 UploadFileInfoMap::const_iterator it = pending_uploads_.find(upload_id);
139 DVLOG_IF(1, it == pending_uploads_.end()) << "No upload found for id " 144 DVLOG_IF(1, it == pending_uploads_.end()) << "No upload found for id "
140 << upload_id; 145 << upload_id;
141 return it != pending_uploads_.end() ? it->second : NULL; 146 return it != pending_uploads_.end() ? it->second : NULL;
142 } 147 }
143 148
144 void GDataUploader::OpenFile(UploadFileInfo* upload_file_info) { 149 void GDataUploader::OpenFile(UploadFileInfo* upload_file_info) {
145 // Open the file asynchronously. 150 // Open the file asynchronously.
146 const int rv = upload_file_info->file_stream->Open( 151 const int rv = upload_file_info->file_stream->Open(
147 upload_file_info->file_path, 152 upload_file_info->file_path,
148 base::PLATFORM_FILE_OPEN | 153 base::PLATFORM_FILE_OPEN |
149 base::PLATFORM_FILE_READ | 154 base::PLATFORM_FILE_READ |
150 base::PLATFORM_FILE_ASYNC, 155 base::PLATFORM_FILE_ASYNC,
151 base::Bind(&GDataUploader::OpenCompletionCallback, 156 base::Bind(&GDataUploader::OpenCompletionCallback,
152 uploader_factory_.GetWeakPtr(), 157 uploader_factory_.GetWeakPtr(),
153 upload_file_info->upload_id)); 158 upload_file_info->upload_id));
154 DCHECK_EQ(net::ERR_IO_PENDING, rv); 159 DCHECK_EQ(net::ERR_IO_PENDING, rv);
155 } 160 }
156 161
157 void GDataUploader::OpenCompletionCallback(int upload_id, int result) { 162 void GDataUploader::OpenCompletionCallback(int upload_id, int result) {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164 base::AutoLock lock(lock_);
159 165
160 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); 166 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id);
161 if (!upload_file_info) 167 if (!upload_file_info)
162 return; 168 return;
163 169
164 // The file may actually not exist yet, as the downloads system downloads 170 // The file may actually not exist yet, as the downloads system downloads
165 // to a temp location and then renames the file. If this is the case, we 171 // to a temp location and then renames the file. If this is the case, we
166 // just retry opening the file later. 172 // just retry opening the file later.
167 if (result != net::OK) { 173 if (result != net::OK) {
168 DCHECK_EQ(result, net::ERR_FILE_NOT_FOUND); 174 DCHECK_EQ(result, net::ERR_FILE_NOT_FOUND);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 base::Bind(&GDataUploader::OnUploadLocationReceived, 207 base::Bind(&GDataUploader::OnUploadLocationReceived,
202 uploader_factory_.GetWeakPtr(), 208 uploader_factory_.GetWeakPtr(),
203 upload_file_info->upload_id)); 209 upload_file_info->upload_id));
204 } 210 }
205 211
206 void GDataUploader::OnUploadLocationReceived( 212 void GDataUploader::OnUploadLocationReceived(
207 int upload_id, 213 int upload_id,
208 GDataErrorCode code, 214 GDataErrorCode code,
209 const GURL& upload_location) { 215 const GURL& upload_location) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217 base::AutoLock lock(lock_);
211 218
212 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); 219 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id);
213 if (!upload_file_info) 220 if (!upload_file_info)
214 return; 221 return;
215 222
216 DVLOG(1) << "Got upload location [" << upload_location.spec() 223 DVLOG(1) << "Got upload location [" << upload_location.spec()
217 << "] for [" << upload_file_info->title << "]"; 224 << "] for [" << upload_file_info->title << "]";
218 225
219 if (code != HTTP_SUCCESS) { 226 if (code != HTTP_SUCCESS) {
220 // TODO(achuith): Handle error codes from Google Docs server. 227 // TODO(achuith): Handle error codes from Google Docs server.
221 UploadFailed(upload_file_info, base::PLATFORM_FILE_ERROR_ABORT); 228 UploadFailed(upload_file_info, base::PLATFORM_FILE_ERROR_ABORT);
222 return; 229 return;
223 } 230 }
224 231
225 upload_file_info->upload_location = upload_location; 232 upload_file_info->upload_location = upload_location;
226 233
227 // Start the upload from the beginning of the file. 234 // Start the upload from the beginning of the file.
228 UploadNextChunk(upload_file_info); 235 UploadNextChunk(upload_file_info);
229 } 236 }
230 237
231 void GDataUploader::UploadNextChunk(UploadFileInfo* upload_file_info) { 238 void GDataUploader::UploadNextChunk(UploadFileInfo* upload_file_info) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240 lock_.AssertAcquired();
241
233 // Check that |upload_file_info| is in pending_uploads_. 242 // Check that |upload_file_info| is in pending_uploads_.
234 DCHECK(upload_file_info == GetUploadFileInfo(upload_file_info->upload_id)); 243 DCHECK(upload_file_info == GetUploadFileInfo(upload_file_info->upload_id));
235 DVLOG(1) << "Number of pending uploads=" << pending_uploads_.size(); 244 DVLOG(1) << "Number of pending uploads=" << pending_uploads_.size();
236 245
237 // Determine number of bytes to read for this upload iteration, which cannot 246 // Determine number of bytes to read for this upload iteration, which cannot
238 // exceed size of buf i.e. buf_len. 247 // exceed size of buf i.e. buf_len.
239 const int64 bytes_remaining = upload_file_info->SizeRemaining(); 248 const int64 bytes_remaining = upload_file_info->SizeRemaining();
240 const int bytes_to_read = std::min(upload_file_info->SizeRemaining(), 249 const int bytes_to_read = std::min(upload_file_info->SizeRemaining(),
241 upload_file_info->buf_len); 250 upload_file_info->buf_len);
242 251
(...skipping 20 matching lines...) Expand all
263 bytes_to_read)); 272 bytes_to_read));
264 } 273 }
265 274
266 void GDataUploader::ReadCompletionCallback( 275 void GDataUploader::ReadCompletionCallback(
267 int upload_id, 276 int upload_id,
268 int bytes_to_read, 277 int bytes_to_read,
269 int bytes_read) { 278 int bytes_read) {
270 // The Read is asynchronously executed on BrowserThread::UI, where 279 // The Read is asynchronously executed on BrowserThread::UI, where
271 // Read() was called. 280 // Read() was called.
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282 base::AutoLock lock(lock_);
283
273 DVLOG(1) << "ReadCompletionCallback bytes read=" << bytes_read; 284 DVLOG(1) << "ReadCompletionCallback bytes read=" << bytes_read;
274 285
275 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); 286 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id);
276 if (!upload_file_info) 287 if (!upload_file_info)
277 return; 288 return;
278 289
279 // TODO(achuith): Handle this error. 290 // TODO(achuith): Handle this error.
280 DCHECK_EQ(bytes_to_read, bytes_read); 291 DCHECK_EQ(bytes_to_read, bytes_read);
281 DCHECK_GT(bytes_read, 0) << "Error reading from file " 292 DCHECK_GT(bytes_read, 0) << "Error reading from file "
282 << upload_file_info->file_path.value(); 293 << upload_file_info->file_path.value();
(...skipping 14 matching lines...) Expand all
297 base::Bind(&GDataUploader::OnResumeUploadResponseReceived, 308 base::Bind(&GDataUploader::OnResumeUploadResponseReceived,
298 uploader_factory_.GetWeakPtr(), 309 uploader_factory_.GetWeakPtr(),
299 upload_file_info->upload_id)); 310 upload_file_info->upload_id));
300 } 311 }
301 312
302 void GDataUploader::OnResumeUploadResponseReceived( 313 void GDataUploader::OnResumeUploadResponseReceived(
303 int upload_id, 314 int upload_id,
304 const ResumeUploadResponse& response, 315 const ResumeUploadResponse& response,
305 scoped_ptr<DocumentEntry> entry) { 316 scoped_ptr<DocumentEntry> entry) {
306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
318 base::AutoLock lock(lock_);
307 319
308 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id); 320 UploadFileInfo* upload_file_info = GetUploadFileInfo(upload_id);
309 if (!upload_file_info) 321 if (!upload_file_info)
310 return; 322 return;
311 323
312 if (response.code == HTTP_CREATED) { 324 if (response.code == HTTP_CREATED) {
313 DVLOG(1) << "Successfully created uploaded file=[" 325 DVLOG(1) << "Successfully created uploaded file=["
314 << upload_file_info->title; 326 << upload_file_info->title;
315 327
316 // Done uploading. 328 // Done uploading.
317 upload_file_info->entry = entry.Pass(); 329 upload_file_info->entry = entry.Pass();
318 if (!upload_file_info->completion_callback.is_null()) { 330 if (!upload_file_info->completion_callback.is_null()) {
319 upload_file_info->completion_callback.Run(base::PLATFORM_FILE_OK, 331 upload_file_info->completion_callback.Run(base::PLATFORM_FILE_OK,
320 upload_file_info); 332 upload_file_info);
321 } 333 }
322 // TODO(achuith): DeleteUpload() here and let clients call 334
323 // GDataFileSystem::AddUploadedFile. 335 // Remove |upload_file_info| from the UploadFileInfoMap. The UploadFileInfo
336 // object will be deleted later upon transfer completion.
337 RemoveUpload(upload_file_info);
324 return; 338 return;
325 } 339 }
326 340
327 // If code is 308 (RESUME_INCOMPLETE) and range_received is what has been 341 // If code is 308 (RESUME_INCOMPLETE) and range_received is what has been
328 // previously uploaded (i.e. = upload_file_info->end_range), proceed to 342 // previously uploaded (i.e. = upload_file_info->end_range), proceed to
329 // upload the next chunk. 343 // upload the next chunk.
330 if (response.code != HTTP_RESUME_INCOMPLETE || 344 if (response.code != HTTP_RESUME_INCOMPLETE ||
331 response.start_range_received != 0 || 345 response.start_range_received != 0 ||
332 response.end_range_received != upload_file_info->end_range) { 346 response.end_range_received != upload_file_info->end_range) {
333 // TODO(achuith): Handle error cases, e.g. 347 // TODO(achuith): Handle error cases, e.g.
(...skipping 13 matching lines...) Expand all
347 DVLOG(1) << "Received range " << response.start_range_received 361 DVLOG(1) << "Received range " << response.start_range_received
348 << "-" << response.end_range_received 362 << "-" << response.end_range_received
349 << " for [" << upload_file_info->title << "]"; 363 << " for [" << upload_file_info->title << "]";
350 364
351 // Continue uploading. 365 // Continue uploading.
352 UploadNextChunk(upload_file_info); 366 UploadNextChunk(upload_file_info);
353 } 367 }
354 368
355 void GDataUploader::MoveFileToCache(UploadFileInfo* upload_file_info) { 369 void GDataUploader::MoveFileToCache(UploadFileInfo* upload_file_info) {
356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
371 lock_.AssertAcquired();
372
357 if (upload_file_info->entry == NULL) 373 if (upload_file_info->entry == NULL)
358 return; 374 return;
359 375
360 DVLOG(1) << "MoveFileToCache " << upload_file_info->file_path.value(); 376 DVLOG(1) << "MoveFileToCache " << upload_file_info->file_path.value();
361 file_system_->AddUploadedFile( 377 file_system_->AddUploadedFile(
362 upload_file_info->gdata_path.DirName(), 378 upload_file_info->gdata_path.DirName(),
363 upload_file_info->entry.get(), 379 upload_file_info->entry.get(),
364 upload_file_info->file_path, 380 upload_file_info->file_path,
365 GDataCache::FILE_OPERATION_MOVE); 381 GDataCache::FILE_OPERATION_MOVE,
366 DeleteUpload(upload_file_info); 382 base::Bind(&GDataUploader::OnAddUploadFileComplete,
383 uploader_factory_.GetWeakPtr(),
384 upload_file_info));
385
386 // Remove |upload_file_info| from the UploadFileInfoMap. The UploadFileInfo
387 // object will be deleted in OnAddUploadFileComplete.
388 RemoveUpload(upload_file_info);
389 }
390
391 void GDataUploader::OnAddUploadFileComplete(UploadFileInfo* upload_file_info) {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 delete upload_file_info;
367 } 394 }
368 395
369 void GDataUploader::UploadFailed(UploadFileInfo* upload_file_info, 396 void GDataUploader::UploadFailed(UploadFileInfo* upload_file_info,
370 base::PlatformFileError error) { 397 base::PlatformFileError error) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
399 lock_.AssertAcquired();
400
372 LOG(ERROR) << "Upload failed " << upload_file_info->DebugString(); 401 LOG(ERROR) << "Upload failed " << upload_file_info->DebugString();
373 if (!upload_file_info->completion_callback.is_null()) { 402 if (!upload_file_info->completion_callback.is_null()) {
374 upload_file_info->completion_callback.Run(error, 403 upload_file_info->completion_callback.Run(error,
375 upload_file_info); 404 upload_file_info);
376 } 405 }
377 DeleteUpload(upload_file_info);
378 }
379 406
380 void GDataUploader::DeleteUpload(UploadFileInfo* upload_file_info) { 407 RemoveUpload(upload_file_info);
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
382
383 DVLOG(1) << "Deleting upload " << upload_file_info->gdata_path.value();
384 pending_uploads_.erase(upload_file_info->upload_id);
385
386 // The file stream is closed by the destructor asynchronously.
387 delete upload_file_info->file_stream;
388 delete upload_file_info; 408 delete upload_file_info;
389 } 409 }
390 410
411 void GDataUploader::RemoveUpload(UploadFileInfo* upload_file_info) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413 lock_.AssertAcquired();
414
415 DVLOG(1) << "Removing upload " << upload_file_info->gdata_path.value();
416 pending_uploads_.erase(upload_file_info->upload_id);
417 }
418
391 } // namespace gdata 419 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_uploader.h ('k') | chrome/browser/chromeos/gdata/mock_gdata_file_system.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698