Commit 9e7e75d5 authored by yoshiki@chromium.org's avatar yoshiki@chromium.org

Files.app: Fix flakiness in chaining directory

I'm about to commit a patch to improve of filelist draw. But it makes some tests flaky because the currently directory changes faster than before. This patch makes the logic of directory changing more robust.

BUG=367123
TEST=browser_test passes

Review URL: https://codereview.chromium.org/312493002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275418 0039d316-1c4b-4281-b951-d872f2087c98
parent 8474014d
...@@ -32,6 +32,8 @@ function DirectoryModel(singleSelection, fileFilter, fileWatcher, ...@@ -32,6 +32,8 @@ function DirectoryModel(singleSelection, fileFilter, fileWatcher,
this.scanFailures_ = 0; this.scanFailures_ = 0;
this.changeDirectorySequence_ = 0; this.changeDirectorySequence_ = 0;
this.directoryChangeQueue_ = new AsyncUtil.Queue();
this.fileFilter_ = fileFilter; this.fileFilter_ = fileFilter;
this.fileFilter_.addEventListener('changed', this.fileFilter_.addEventListener('changed',
this.onFilterChanged_.bind(this)); this.onFilterChanged_.bind(this));
...@@ -278,8 +280,14 @@ DirectoryModel.prototype.scheduleRescan = function(delay) { ...@@ -278,8 +280,14 @@ DirectoryModel.prototype.scheduleRescan = function(delay) {
clearTimeout(this.rescanTimeoutId_); clearTimeout(this.rescanTimeoutId_);
} }
var sequence = this.changeDirectorySequence_;
this.rescanTime_ = Date.now() + delay; this.rescanTime_ = Date.now() + delay;
this.rescanTimeoutId_ = setTimeout(this.rescan.bind(this), delay); this.rescanTimeoutId_ = setTimeout(function() {
this.rescanTimeoutId_ = null;
if (sequence === this.changeDirectorySequence_)
this.rescan();
}.bind(this), delay);
}; };
/** /**
...@@ -312,9 +320,13 @@ DirectoryModel.prototype.rescan = function() { ...@@ -312,9 +320,13 @@ DirectoryModel.prototype.rescan = function() {
var dirContents = this.currentDirContents_.clone(); var dirContents = this.currentDirContents_.clone();
dirContents.setFileList([]); dirContents.setFileList([]);
var sequence = this.changeDirectorySequence_;
var successCallback = (function() { var successCallback = (function() {
this.replaceDirectoryContents_(dirContents); if (sequence === this.changeDirectorySequence_) {
cr.dispatchSimpleEvent(this, 'rescan-completed'); this.replaceDirectoryContents_(dirContents);
cr.dispatchSimpleEvent(this, 'rescan-completed');
}
}).bind(this); }).bind(this);
this.scan_(dirContents, this.scan_(dirContents,
...@@ -329,11 +341,12 @@ DirectoryModel.prototype.rescan = function() { ...@@ -329,11 +341,12 @@ DirectoryModel.prototype.rescan = function() {
* *
* @param {DirectoryContentes} newDirContents New DirectoryContents instance to * @param {DirectoryContentes} newDirContents New DirectoryContents instance to
* replace currentDirContents_. * replace currentDirContents_.
* @param {function()=} opt_callback Called on success. * @param {function(boolean)} callback Callback with result. True if the scan
* is completed successfully, false if the scan is failed.
* @private * @private
*/ */
DirectoryModel.prototype.clearAndScan_ = function(newDirContents, DirectoryModel.prototype.clearAndScan_ = function(newDirContents,
opt_callback) { callback) {
if (this.currentDirContents_.isScanning()) if (this.currentDirContents_.isScanning())
this.currentDirContents_.cancelScan(); this.currentDirContents_.cancelScan();
this.currentDirContents_ = newDirContents; this.currentDirContents_ = newDirContents;
...@@ -348,22 +361,46 @@ DirectoryModel.prototype.clearAndScan_ = function(newDirContents, ...@@ -348,22 +361,46 @@ DirectoryModel.prototype.clearAndScan_ = function(newDirContents,
this.runningScan_ = null; this.runningScan_ = null;
} }
var sequence = this.changeDirectorySequence_;
var cancelled = false;
var onDone = function() { var onDone = function() {
if (cancelled)
return;
cr.dispatchSimpleEvent(this, 'scan-completed'); cr.dispatchSimpleEvent(this, 'scan-completed');
if (opt_callback) callback(true);
opt_callback();
}.bind(this); }.bind(this);
var onFailed = function() { var onFailed = function() {
if (cancelled)
return;
cr.dispatchSimpleEvent(this, 'scan-failed'); cr.dispatchSimpleEvent(this, 'scan-failed');
callback(false);
}.bind(this); }.bind(this);
var onUpdated = function() { var onUpdated = function() {
if (cancelled)
return;
if (this.changeDirectorySequence_ !== sequence) {
cancelled = true;
cr.dispatchSimpleEvent(this, 'scan-cancelled');
callback(false);
return;
}
cr.dispatchSimpleEvent(this, 'scan-updated'); cr.dispatchSimpleEvent(this, 'scan-updated');
}.bind(this); }.bind(this);
var onCancelled = function() { var onCancelled = function() {
if (cancelled)
return;
cancelled = true;
cr.dispatchSimpleEvent(this, 'scan-cancelled'); cr.dispatchSimpleEvent(this, 'scan-cancelled');
callback(false);
}.bind(this); }.bind(this);
// Clear the table, and start scanning. // Clear the table, and start scanning.
...@@ -602,8 +639,7 @@ DirectoryModel.prototype.createDirectory = function(name, ...@@ -602,8 +639,7 @@ DirectoryModel.prototype.createDirectory = function(name,
return; return;
} }
var tracker = this.createDirectoryChangeTracker(); var sequence = this.changeDirectorySequence_;
tracker.start();
new Promise(entry.getDirectory.bind( new Promise(entry.getDirectory.bind(
entry, name, {create: true, exclusive: true})). entry, name, {create: true, exclusive: true})).
...@@ -621,8 +657,7 @@ DirectoryModel.prototype.createDirectory = function(name, ...@@ -621,8 +657,7 @@ DirectoryModel.prototype.createDirectory = function(name,
then(function(newEntry) { then(function(newEntry) {
// Do not change anything or call the callback if current // Do not change anything or call the callback if current
// directory changed. // directory changed.
tracker.stop(); if (this.changeDirectorySequence_ !== sequence) {
if (tracker.hasChanged) {
abortCallback(); abortCallback();
return; return;
} }
...@@ -641,7 +676,6 @@ DirectoryModel.prototype.createDirectory = function(name, ...@@ -641,7 +676,6 @@ DirectoryModel.prototype.createDirectory = function(name,
successCallback(newEntry); successCallback(newEntry);
} }
}.bind(this), function(reason) { }.bind(this), function(reason) {
tracker.stop();
errorCallback(reason); errorCallback(reason);
}); });
}; };
...@@ -668,26 +702,38 @@ DirectoryModel.prototype.changeDirectoryEntry = function( ...@@ -668,26 +702,38 @@ DirectoryModel.prototype.changeDirectoryEntry = function(
this.changeDirectorySequence_++; this.changeDirectorySequence_++;
this.clearSearch_(); this.clearSearch_();
var promise = new Promise( this.directoryChangeQueue_.run(function(sequence, queueTaskCallback) {
function(onFulfilled, onRejected) { this.fileWatcher_.changeWatchedDirectory(
this.fileWatcher_.changeWatchedDirectory(dirEntry, onFulfilled); dirEntry,
}.bind(this)). function() {
if (this.changeDirectorySequence_ !== sequence) {
then(function(sequence) { queueTaskCallback();
return new Promise(function(onFulfilled, onRejected) {
if (this.changeDirectorySequence_ !== sequence)
return; return;
}
var newDirectoryContents = this.createDirectoryContents_( var newDirectoryContents = this.createDirectoryContents_(
this.currentFileListContext_, dirEntry, ''); this.currentFileListContext_, dirEntry, '');
if (!newDirectoryContents) if (!newDirectoryContents) {
queueTaskCallback();
return; return;
}
var previousDirEntry = this.currentDirContents_.getDirectoryEntry(); var previousDirEntry =
this.clearAndScan_(newDirectoryContents, opt_callback); this.currentDirContents_.getDirectoryEntry();
this.clearAndScan_(
// For tests that open the dialog to empty directories, everything is newDirectoryContents,
// loaded at this point. function(result) {
// Calls the callback of the method when successful.
if (result && opt_callback)
opt_callback();
// Notify that the current task of this.directoryChangeQueue_
// is completed.
setTimeout(queueTaskCallback);
});
// For tests that open the dialog to empty directories, everything
// is loaded at this point.
util.testSendMessage('directory-change-complete'); util.testSendMessage('directory-change-complete');
var event = new Event('directory-changed'); var event = new Event('directory-changed');
...@@ -695,7 +741,7 @@ DirectoryModel.prototype.changeDirectoryEntry = function( ...@@ -695,7 +741,7 @@ DirectoryModel.prototype.changeDirectoryEntry = function(
event.newDirEntry = dirEntry; event.newDirEntry = dirEntry;
this.dispatchEvent(event); this.dispatchEvent(event);
}.bind(this)); }.bind(this));
}.bind(this, this.changeDirectorySequence_)); }.bind(this, this.changeDirectorySequence_));
}; };
/** /**
...@@ -903,25 +949,41 @@ DirectoryModel.prototype.search = function(query, ...@@ -903,25 +949,41 @@ DirectoryModel.prototype.search = function(query,
return; return;
} }
if (!(query || '').trimLeft()) { this.changeDirectorySequence_++;
if (this.isSearching()) { this.directoryChangeQueue_.run(function(sequence, callback) {
var newDirContents = this.createDirectoryContents_( if (this.changeDirectorySequence_ !== sequence) {
this.currentFileListContext_, callback();
currentDirEntry); return;
this.clearAndScan_(newDirContents); }
if (!(query || '').trimLeft()) {
if (this.isSearching()) {
var newDirContents = this.createDirectoryContents_(
this.currentFileListContext_,
currentDirEntry);
this.clearAndScan_(newDirContents,
sequence,
callback);
} else {
callback();
}
return;
} }
return;
}
var newDirContents = this.createDirectoryContents_( var newDirContents = this.createDirectoryContents_(
this.currentFileListContext_, currentDirEntry, query); this.currentFileListContext_, currentDirEntry, query);
if (!newDirContents) if (!newDirContents) {
return; callback();
return;
}
this.onSearchCompleted_ = onSearchRescan; this.onSearchCompleted_ = onSearchRescan;
this.onClearSearch_ = onClearSearch; this.onClearSearch_ = onClearSearch;
this.addEventListener('scan-completed', this.onSearchCompleted_); this.addEventListener('scan-completed', this.onSearchCompleted_);
this.clearAndScan_(newDirContents); this.clearAndScan_(newDirContents,
sequence,
callback);
}.bind(this, this.changeDirectorySequence_));
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment