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

Side by Side Diff: chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc

Issue 11414221: Media Galleries: On Linux, write data to snapshots in chunks rather than at once. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/media_gallery/mtp_device_delegate_impl_linux.h" 5 #include "chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h"
6 6
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10
7 #include "base/bind.h" 11 #include "base/bind.h"
8 #include "base/file_path.h" 12 #include "base/file_path.h"
9 #include "base/file_util.h" 13 #include "base/file_util.h"
10 #include "base/sequenced_task_runner.h" 14 #include "base/sequenced_task_runner.h"
11 #include "base/sequenced_task_runner_helpers.h" 15 #include "base/sequenced_task_runner_helpers.h"
12 #include "base/string_util.h" 16 #include "base/string_util.h"
13 #include "base/synchronization/cancellation_flag.h" 17 #include "base/synchronization/cancellation_flag.h"
14 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/threading/sequenced_worker_pool.h"
15 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager .h" 19 #include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager .h"
16 #include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h" 20 #include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h"
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 349
346 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); 350 DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker);
347 }; 351 };
348 352
349 // Worker class to read media device file data given a file |path|. 353 // Worker class to read media device file data given a file |path|.
350 class ReadFileWorker 354 class ReadFileWorker
351 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { 355 : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> {
352 public: 356 public:
353 // Constructed on |media_task_runner_| thread. 357 // Constructed on |media_task_runner_| thread.
354 ReadFileWorker(const std::string& handle, 358 ReadFileWorker(const std::string& handle,
355 const std::string& path, 359 const std::string& src_path,
356 uint32 total_size, 360 uint32 total_size,
361 const FilePath& dest_path,
357 SequencedTaskRunner* task_runner, 362 SequencedTaskRunner* task_runner,
358 WaitableEvent* task_completed_event, 363 WaitableEvent* task_completed_event,
359 WaitableEvent* shutdown_event) 364 WaitableEvent* shutdown_event)
360 : device_handle_(handle), 365 : device_handle_(handle),
361 path_(path), 366 src_path_(src_path),
362 total_bytes_(total_size), 367 total_bytes_(total_size),
368 dest_path_(dest_path),
369 dest_fd_(-1),
370 bytes_read_(0),
363 error_occurred_(false), 371 error_occurred_(false),
364 media_task_runner_(task_runner), 372 media_task_runner_(task_runner),
365 on_task_completed_event_(task_completed_event), 373 on_task_completed_event_(task_completed_event),
366 on_shutdown_event_(shutdown_event) { 374 on_shutdown_event_(shutdown_event) {
367 DCHECK(on_task_completed_event_); 375 DCHECK(on_task_completed_event_);
368 DCHECK(on_shutdown_event_); 376 DCHECK(on_shutdown_event_);
369 } 377 }
370 378
371 // This function is invoked on |media_task_runner_| to post the task on UI 379 // This function is invoked on |media_task_runner_| to post the task on UI
372 // thread. This blocks the |media_task_runner_| until the task is complete. 380 // thread. This blocks the |media_task_runner_| until the task is complete.
373 void Run() { 381 void Run() {
374 if (on_shutdown_event_->IsSignaled()) { 382 if (on_shutdown_event_->IsSignaled()) {
375 // Process is in shutdown mode. 383 // Process is in shutdown mode.
376 // Do not post any task on |media_task_runner_|. 384 // Do not post any task on |media_task_runner_|.
377 return; 385 return;
378 } 386 }
379 387
380 while (!error_occurred_ && (data_.size() < total_bytes_) && 388 dest_fd_ = open(dest_path_.value().c_str(), O_WRONLY);
381 !cancel_tasks_flag_.IsSet()) { 389 if (dest_fd_ < 0)
390 return;
391 dest_fd_scoper_.reset(&dest_fd_);
392
393 while (!error_occurred_ && (bytes_read_ < total_bytes_)) {
382 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 394 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
383 Bind(&ReadFileWorker::DoWorkOnUIThread, this)); 395 Bind(&ReadFileWorker::DoWorkOnUIThread, this));
384 on_task_completed_event_->Wait(); 396 on_task_completed_event_->Wait();
385 if (on_shutdown_event_->IsSignaled()) 397 if (on_shutdown_event_->IsSignaled()) {
386 cancel_tasks_flag_.Set(); 398 cancel_tasks_flag_.Set();
399 break;
400 }
kmadhusu 2012/11/30 02:05:12 When the MTR resumes, if |error_occured_| is true,
Lei Zhang 2012/11/30 02:30:55 Done.
401 int bytes_written =
402 file_util::WriteFileDescriptor(dest_fd_, data_.data(), data_.size());
403 if (static_cast<int>(data_.size()) != bytes_written) {
404 error_occurred_ = true;
405 break;
406 }
407 bytes_read_ += data_.size();
387 } 408 }
388 } 409 }
389 410
390 // Returns the media file contents received from mtpd. 411 bool Succeeded() const {
391 const std::string& data() const { return data_; } 412 return !error_occurred_ && bytes_read_ == total_bytes_;
kmadhusu 2012/11/30 02:05:12 nit: () around binary expressions.
Lei Zhang 2012/11/30 02:30:55 Done.
413 }
392 414
393 // Returns the |media_task_runner_| associated with this worker object. 415 // Returns the |media_task_runner_| associated with this worker object.
394 // This function is exposed for WorkerDeleter struct to access the 416 // This function is exposed for WorkerDeleter struct to access the
395 // |media_task_runner_|. 417 // |media_task_runner_|.
396 SequencedTaskRunner* media_task_runner() const { 418 SequencedTaskRunner* media_task_runner() const {
397 return media_task_runner_.get(); 419 return media_task_runner_.get();
398 } 420 }
399 421
400 private: 422 private:
401 friend struct WorkerDeleter<ReadFileWorker>; 423 friend struct WorkerDeleter<ReadFileWorker>;
402 friend class DeleteHelper<ReadFileWorker>; 424 friend class DeleteHelper<ReadFileWorker>;
403 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; 425 friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>;
404 426
405 // Destructed via ReadFileWorkerDeleter. 427 // Destructed via ReadFileWorkerDeleter.
406 virtual ~ReadFileWorker() { 428 virtual ~ReadFileWorker() {
407 // This object must be destructed on |media_task_runner_|. 429 // This object must be destructed on |media_task_runner_|.
408 } 430 }
409 431
410 // Dispatches a request to MediaTransferProtocolManager to get the media file 432 // Dispatches a request to MediaTransferProtocolManager to get the media file
411 // contents. 433 // contents.
412 void DoWorkOnUIThread() { 434 void DoWorkOnUIThread() {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414 if (cancel_tasks_flag_.IsSet()) 436 if (cancel_tasks_flag_.IsSet())
415 return; 437 return;
416 438
417 GetMediaTransferProtocolManager()->ReadFileChunkByPath( 439 GetMediaTransferProtocolManager()->ReadFileChunkByPath(
418 device_handle_, path_, data_.size(), BytesToRead(), 440 device_handle_, src_path_, bytes_read_, BytesToRead(),
419 Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); 441 Bind(&ReadFileWorker::OnDidWorkOnUIThread, this));
420 } 442 }
421 443
422 // Query callback for DoWorkOnUIThread(). On success, |data| has the media 444 // Query callback for DoWorkOnUIThread(). On success, |data| has the media
423 // file contents. On failure, |error| is set to true. This function signals 445 // file contents. On failure, |error| is set to true. This function signals
424 // to unblock |media_task_runner_|. 446 // to unblock |media_task_runner_|.
425 void OnDidWorkOnUIThread(const std::string& data, bool error) { 447 void OnDidWorkOnUIThread(const std::string& data, bool error) {
426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
427 if (cancel_tasks_flag_.IsSet()) 449 if (cancel_tasks_flag_.IsSet())
428 return; 450 return;
429 451
430 error_occurred_ = error; 452 error_occurred_ = error || (data.size() != BytesToRead());
431 if (!error) { 453 if (!error_occurred_)
kmadhusu 2012/11/30 02:05:12 If |error_occurred_| is true, we should reset |dat
Lei Zhang 2012/11/30 02:30:55 I fixed the checks above so that won't happen.
432 if ((BytesToRead() == data.size())) { 454 data_ = data;
433 // TODO(kmadhusu): Data could be really huge. Consider passing data by
434 // pointer/ref rather than by value here to avoid an extra data copy.
435 data_.append(data);
436 } else {
437 NOTREACHED();
438 error_occurred_ = true;
439 }
440 }
441 on_task_completed_event_->Signal(); 455 on_task_completed_event_->Signal();
442 } 456 }
443 457
444 uint32 BytesToRead() const { 458 uint32 BytesToRead() const {
445 // Read data in 1 MB chunks. 459 // Read data in 1 MB chunks.
446 static const uint32 kReadChunkSize = 1024 * 1024; 460 static const uint32 kReadChunkSize = 1024 * 1024;
447 return std::min(kReadChunkSize, 461 return std::min(kReadChunkSize, total_bytes_ - bytes_read_);
448 total_bytes_ - static_cast<uint32>(data_.size()));
449 } 462 }
450 463
451 // The device unique identifier to query the device. 464 // The device unique identifier to query the device.
452 const std::string device_handle_; 465 const std::string device_handle_;
453 466
454 // The media device file path. 467 // The media device file path.
455 const std::string path_; 468 const std::string src_path_;
456
457 // The data from mtpd.
458 std::string data_;
459 469
460 // Number of bytes to read. 470 // Number of bytes to read.
461 const uint32 total_bytes_; 471 const uint32 total_bytes_;
462 472
473 // Where to write the data read from the device.
474 const FilePath dest_path_;
475
476 // File descriptor for |dest_path_|.
477 int dest_fd_;
478
479 // Scoper to cleanup |dest_fd_|.
480 file_util::ScopedFD dest_fd_scoper_;
kmadhusu 2012/11/30 02:05:12 Is there any specific reason to have |dest_fd_| an
Lei Zhang 2012/11/30 02:30:55 Not needed any more. Removed.
481
482 /*****************************************************************************
483 * The variables below are accessed on both |media_task_runner_| and the UI
484 * thread. However, there's no concurrent access because the UI thread is in a
485 * blocked state when access occurs on |media_task_runner_|.
486 */
487
488 // Number of bytes read from the device.
489 uint32 bytes_read_;
490
491 // Temporary data storage.
492 std::string data_;
493
463 // Whether an error occurred during file transfer. 494 // Whether an error occurred during file transfer.
464 bool error_occurred_; 495 bool error_occurred_;
465 496
497 /****************************************************************************/
498
466 // A reference to |media_task_runner_| to destruct this object on the correct 499 // A reference to |media_task_runner_| to destruct this object on the correct
467 // thread. 500 // thread.
468 scoped_refptr<SequencedTaskRunner> media_task_runner_; 501 scoped_refptr<SequencedTaskRunner> media_task_runner_;
469 502
470 // |media_task_runner_| can wait on this event until the required operation 503 // |media_task_runner_| can wait on this event until the required operation
471 // is complete. 504 // is complete.
472 // TODO(kmadhusu): Remove this WaitableEvent after modifying the 505 // TODO(kmadhusu): Remove this WaitableEvent after modifying the
473 // DeviceMediaFileUtil functions as asynchronous functions. 506 // DeviceMediaFileUtil functions as asynchronous functions.
474 WaitableEvent* on_task_completed_event_; 507 WaitableEvent* on_task_completed_event_;
475 508
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 PlatformFileError error = GetFileInfo(device_file_path, file_info); 886 PlatformFileError error = GetFileInfo(device_file_path, file_info);
854 if (error != base::PLATFORM_FILE_OK) 887 if (error != base::PLATFORM_FILE_OK)
855 return error; 888 return error;
856 889
857 if (file_info->size <= 0 || file_info->size > kuint32max) 890 if (file_info->size <= 0 || file_info->size > kuint32max)
858 return base::PLATFORM_FILE_ERROR_FAILED; 891 return base::PLATFORM_FILE_ERROR_FAILED;
859 892
860 scoped_refptr<ReadFileWorker> worker(new ReadFileWorker( 893 scoped_refptr<ReadFileWorker> worker(new ReadFileWorker(
861 device_handle_, 894 device_handle_,
862 GetDeviceRelativePath(device_path_, device_file_path.value()), 895 GetDeviceRelativePath(device_path_, device_file_path.value()),
863 file_info->size, 896 file_info->size, local_path,
864 media_task_runner_, &on_task_completed_event_, &on_shutdown_event_)); 897 media_task_runner_, &on_task_completed_event_, &on_shutdown_event_));
kmadhusu 2012/11/30 02:05:12 nit: some of these params can fit in the previous
Lei Zhang 2012/11/30 02:30:55 Done. That could have been said of the previous co
865 worker->Run(); 898 worker->Run();
866 899
867 const std::string& file_data = worker->data(); 900 if (!worker->Succeeded())
868 int data_size = static_cast<int>(file_data.length());
869 if (file_data.empty() ||
870 file_util::WriteFile(local_path, file_data.c_str(),
871 data_size) != data_size) {
872 return base::PLATFORM_FILE_ERROR_FAILED; 901 return base::PLATFORM_FILE_ERROR_FAILED;
873 }
874 902
875 // Modify the last modified time to null. This prevents the time stamp 903 // Modify the last modified time to null. This prevents the time stamp
876 // verfication in LocalFileStreamReader. 904 // verfication in LocalFileStreamReader.
877 file_info->last_modified = base::Time(); 905 file_info->last_modified = base::Time();
878 return error; 906 return base::PLATFORM_FILE_OK;
879 } 907 }
880 908
881 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { 909 SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() {
882 return media_task_runner_.get(); 910 return media_task_runner_.get();
883 } 911 }
884 912
885 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { 913 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
886 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 914 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
887 // Caution: This function is called on the IO thread. Access only the thread 915 // Caution: This function is called on the IO thread. Access only the thread
888 // safe member variables in this function. Do all the clean up operations in 916 // safe member variables in this function. Do all the clean up operations in
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
929 } 957 }
930 958
931 void MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner() { 959 void MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner() {
932 DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); 960 DCHECK(media_task_runner_->RunsTasksOnCurrentThread());
933 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 961 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
934 Bind(&CloseStorageOnUIThread, device_handle_)); 962 Bind(&CloseStorageOnUIThread, device_handle_));
935 delete this; 963 delete this;
936 } 964 }
937 965
938 } // namespace chrome 966 } // namespace chrome
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698