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

Unified Diff: ui/file_manager/file_manager/background/js/file_operation_manager.js

Issue 1085823002: Run copy operations in parallel when destinations are different volumes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fails with an error when volume info is not available. Created 5 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | ui/file_manager/file_manager/background/js/file_operation_manager_unittest.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/file_manager/file_manager/background/js/file_operation_manager.js
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager.js b/ui/file_manager/file_manager/background/js/file_operation_manager.js
index 28d4312a570095f0e3bbf3eaec89998450ec53bc..4c3baa209a3f6973f3ae6f9bba2869346f8fddc9 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager.js
@@ -17,9 +17,18 @@ function FileOperationManager(volumeManager) {
this.volumeManager_ = volumeManager;
/**
+ * List of pending copy tasks. The manager can execute tasks in arbitary
+ * order.
* @private {!Array<!fileOperationUtil.Task>}
*/
- this.copyTasks_ = [];
+ this.pendingCopyTasks_ = [];
+
+ /**
+ * Map of volume id and running copy task. The key is a volume id and the
+ * value is a copy task.
+ * @private {!Object<string,!fileOperationUtil.Task>}
+ */
+ this.runningCopyTasks_ = {};
/**
* @private {!Array<!fileOperationUtil.Task>}
@@ -39,6 +48,14 @@ function FileOperationManager(volumeManager) {
}
/**
+ * Returns pending copy tasks for testing.
+ * @return {!Array<!fileOperationUtil.Task>} Pending copy tasks.
+ */
+FileOperationManager.prototype.getPendingCopyTasksForTesting = function() {
+ return this.pendingCopyTasks_;
+};
+
+/**
* Adds an event listener for the tasks.
* @param {string} type The name of the event.
* @param {EventListenerType} handler The handler for the event. This is called
@@ -64,17 +81,9 @@ FileOperationManager.prototype.removeEventListener = function(type, handler) {
* @return {boolean} True, if there are any tasks.
*/
FileOperationManager.prototype.hasQueuedTasks = function() {
- return this.copyTasks_.length > 0 || this.deleteTasks_.length > 0;
-};
-
-/**
- * Completely clear out the copy queue, either because we encountered an error
- * or completed successfully.
- *
- * @private
- */
-FileOperationManager.prototype.resetQueue_ = function() {
- this.copyTasks_ = [];
+ return Object.keys(this.runningCopyTasks_).length > 0 ||
+ this.pendingCopyTasks_.length > 0 ||
+ this.deleteTasks_.length > 0;
};
/**
@@ -83,20 +92,26 @@ FileOperationManager.prototype.resetQueue_ = function() {
*/
FileOperationManager.prototype.requestTaskCancel = function(taskId) {
var task = null;
- for (var i = 0; i < this.copyTasks_.length; i++) {
- task = this.copyTasks_[i];
+
+ // If the task is not on progress, remove it immediately.
+ for (var i = 0; i < this.pendingCopyTasks_.length; i++) {
+ task = this.pendingCopyTasks_[i];
if (task.taskId !== taskId)
continue;
task.requestCancel();
- // If the task is not on progress, remove it immediately.
- if (i !== 0) {
- this.eventRouter_.sendProgressEvent(
- fileOperationUtil.EventRouter.EventType.CANCELED,
- task.getStatus(),
- task.taskId);
- this.copyTasks_.splice(i, 1);
- }
+ this.eventRouter_.sendProgressEvent(
+ fileOperationUtil.EventRouter.EventType.CANCELED,
+ task.getStatus(),
+ task.taskId);
+ this.pendingCopyTasks_.splice(i, 1);
}
+
+ for (var volumeId in this.runningCopyTasks_) {
+ task = this.runningCopyTasks_[volumeId];
+ if (task.taskId === taskId)
+ task.requestCancel();
+ }
+
for (var i = 0; i < this.deleteTasks_.length; i++) {
task = this.deleteTasks_[i];
if (task.taskId !== taskId)
@@ -216,43 +231,84 @@ FileOperationManager.prototype.queueCopy_ = function(
fileOperationUtil.EventRouter.EventType.BEGIN,
task.getStatus(),
task.taskId);
+
task.initialize(function() {
- this.copyTasks_.push(task);
- if (this.copyTasks_.length === 1)
- this.serviceAllTasks_();
+ this.pendingCopyTasks_.push(task);
+ this.serviceAllTasks_();
}.bind(this));
};
/**
* Service all pending tasks, as well as any that might appear during the
- * copy.
+ * copy. We allow to run tasks in parallel when destinations are different
+ * volumes.
*
* @private
*/
FileOperationManager.prototype.serviceAllTasks_ = function() {
- if (!this.copyTasks_.length) {
+ if (this.pendingCopyTasks_.length === 0 &&
+ Object.keys(this.runningCopyTasks_).length === 0) {
// All tasks have been serviced, clean up and exit.
chrome.power.releaseKeepAwake();
- this.resetQueue_();
return;
}
// Prevent the system from sleeping while copy is in progress.
chrome.power.requestKeepAwake('system');
- var onTaskProgress = function() {
+ // Find next task which can run at now.
+ var nextTask = null;
+ var nextTaskVolumeId = null;
+ for (var i = 0; i < this.pendingCopyTasks_.length; i++) {
+ var task = this.pendingCopyTasks_[i];
+
+ // Fails a copy task of which it fails to get volume info. The destination
+ // volume might be already unmounted.
+ var volumeInfo = this.volumeManager_.getVolumeInfo(task.targetDirEntry);
+ if (volumeInfo === null) {
+ this.eventRouter_.sendProgressEvent(
+ fileOperationUtil.EventRouter.EventType.ERROR,
+ task.getStatus(),
+ task.taskId,
+ new fileOperationUtil.Error(
+ util.FileOperationErrorType.FILESYSTEM_ERROR,
+ util.createDOMError(util.FileError.NOT_FOUND_ERR)));
+
+ this.pendingCopyTasks_.splice(i, 1);
+ i--;
+
+ continue;
+ }
+
+ // When no task is running for the volume, run the task.
+ if (!this.runningCopyTasks_[volumeInfo.volumeId]) {
+ nextTask = this.pendingCopyTasks_.splice(i, 1)[0];
+ nextTaskVolumeId = volumeInfo.volumeId;
+ break;
+ }
+ }
+
+ // There is no task which can run at now.
+ if (nextTask === null)
+ return;
+
+ var onTaskProgress = function(task) {
this.eventRouter_.sendProgressEvent(
fileOperationUtil.EventRouter.EventType.PROGRESS,
- this.copyTasks_[0].getStatus(),
- this.copyTasks_[0].taskId);
- }.bind(this);
+ task.getStatus(),
+ task.taskId);
+ }.bind(this, nextTask);
var onEntryChanged = function(kind, entry) {
this.eventRouter_.sendEntryChangedEvent(kind, entry);
}.bind(this);
- var onTaskError = function(err) {
- var task = this.copyTasks_.shift();
+ // Since getVolumeInfo of targetDirEntry might not be available when this
+ // callback is called, bind volume id here.
+ var onTaskError = function(volumeId, err) {
+ var task = this.runningCopyTasks_[volumeId];
+ delete this.runningCopyTasks_[volumeId];
+
var reason = err.data.name === util.FileError.ABORT_ERR ?
fileOperationUtil.EventRouter.EventType.CANCELED :
fileOperationUtil.EventRouter.EventType.ERROR;
@@ -261,19 +317,22 @@ FileOperationManager.prototype.serviceAllTasks_ = function() {
task.taskId,
err);
this.serviceAllTasks_();
- }.bind(this);
+ }.bind(this, nextTaskVolumeId);
+
+ var onTaskSuccess = function(volumeId) {
+ var task = this.runningCopyTasks_[volumeId];
+ delete this.runningCopyTasks_[volumeId];
- var onTaskSuccess = function() {
- // The task at the front of the queue is completed. Pop it from the queue.
- var task = this.copyTasks_.shift();
this.eventRouter_.sendProgressEvent(
fileOperationUtil.EventRouter.EventType.SUCCESS,
task.getStatus(),
task.taskId);
this.serviceAllTasks_();
- }.bind(this);
+ }.bind(this, nextTaskVolumeId);
+
+ // Add to running tasks and run it.
+ this.runningCopyTasks_[nextTaskVolumeId] = nextTask;
- var nextTask = this.copyTasks_[0];
this.eventRouter_.sendProgressEvent(
fileOperationUtil.EventRouter.EventType.PROGRESS,
nextTask.getStatus(),
@@ -414,9 +473,8 @@ FileOperationManager.prototype.zipSelection = function(
zipTask.getStatus(),
zipTask.taskId);
zipTask.initialize(function() {
- this.copyTasks_.push(zipTask);
- if (this.copyTasks_.length == 1)
- this.serviceAllTasks_();
+ this.pendingCopyTasks_.push(zipTask);
+ this.serviceAllTasks_();
}.bind(this));
};
« no previous file with comments | « no previous file | ui/file_manager/file_manager/background/js/file_operation_manager_unittest.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698