| Index: ui/file_manager/file_manager/background/js/duplicate_finder.js
|
| diff --git a/ui/file_manager/file_manager/background/js/duplicate_finder.js b/ui/file_manager/file_manager/background/js/duplicate_finder.js
|
| index b05799b010422378ae7840aadf16c66b1af5e6b7..cd8f12d05f9c8266b4efa663f94ad765851480a1 100644
|
| --- a/ui/file_manager/file_manager/background/js/duplicate_finder.js
|
| +++ b/ui/file_manager/file_manager/background/js/duplicate_finder.js
|
| @@ -20,6 +20,13 @@ importer.DriveDuplicateFinder = function(tracker) {
|
|
|
| /** @private {Promise<string>} */
|
| this.driveIdPromise_ = null;
|
| +
|
| + /**
|
| + * An bounded cache of most recently calculated file content hashcodes.
|
| + * @private {!LRUCache<!Promise<string>>}
|
| + */
|
| + this.hashCache_ = new LRUCache(
|
| + importer.DriveDuplicateFinder.MAX_CACHED_HASHCODES_);
|
| };
|
|
|
| /**
|
| @@ -45,42 +52,57 @@ importer.DriveDuplicateFinder.HASH_EVENT_THRESHOLD_ = 5000;
|
| /** @private @const {number} */
|
| importer.DriveDuplicateFinder.SEARCH_EVENT_THRESHOLD_ = 1000;
|
|
|
| +/** @private @const {number} */
|
| +importer.DriveDuplicateFinder.MAX_CACHED_HASHCODES_ = 10000;
|
| +
|
| /**
|
| * Computes the content hash for the given file entry.
|
| * @param {!FileEntry} entry
|
| + * @return {!Promise<string>} The computed hash.
|
| * @private
|
| */
|
| importer.DriveDuplicateFinder.prototype.computeHash_ = function(entry) {
|
| - return new Promise(
|
| - /** @this {importer.DriveDuplicateFinder} */
|
| - function(resolve, reject) {
|
| - var startTime = new Date().getTime();
|
| - chrome.fileManagerPrivate.computeChecksum(
|
| - entry.toURL(),
|
| - /**
|
| - * @param {string} result The content hash.
|
| - * @this {importer.DriveDuplicateFinder}
|
| - */
|
| - function(result) {
|
| - var elapsedTime = new Date().getTime() - startTime;
|
| - // Send the timing to GA only if it is sorta exceptionally long.
|
| - // A one second, CPU intensive operation, is pretty long.
|
| - if (elapsedTime >=
|
| - importer.DriveDuplicateFinder.HASH_EVENT_THRESHOLD_) {
|
| - console.info(
|
| - 'Content hash computation took ' + elapsedTime + ' ms.');
|
| - this.tracker_.sendTiming(
|
| - metrics.Categories.ACQUISITION,
|
| - metrics.timing.Variables.COMPUTE_HASH,
|
| - elapsedTime);
|
| - }
|
| - if (chrome.runtime.lastError) {
|
| - reject(chrome.runtime.lastError);
|
| - } else {
|
| - resolve(result);
|
| - }
|
| - }.bind(this));
|
| - }.bind(this));
|
| + return importer.createMetadataHashcode(entry).then(function(hashcode) {
|
| + // Cache key is the concatination of metadata hashcode and URL.
|
| + var cacheKey = hashcode + '|' + entry.toURL();
|
| + if (this.hashCache_.hasKey(cacheKey)) {
|
| + return this.hashCache_.get(cacheKey);
|
| + }
|
| +
|
| + var hashPromise = new Promise(
|
| + /** @this {importer.DriveDuplicateFinder} */
|
| + function(resolve, reject) {
|
| + var startTime = new Date().getTime();
|
| + chrome.fileManagerPrivate.computeChecksum(
|
| + entry.toURL(),
|
| + /**
|
| + * @param {string} result The content hash.
|
| + * @this {importer.DriveDuplicateFinder}
|
| + */
|
| + function(result) {
|
| + var elapsedTime = new Date().getTime() - startTime;
|
| + // Send the timing to GA only if it is sorta exceptionally long.
|
| + // A one second, CPU intensive operation, is pretty long.
|
| + if (elapsedTime >=
|
| + importer.DriveDuplicateFinder.HASH_EVENT_THRESHOLD_) {
|
| + console.info(
|
| + 'Content hash computation took ' + elapsedTime + ' ms.');
|
| + this.tracker_.sendTiming(
|
| + metrics.Categories.ACQUISITION,
|
| + metrics.timing.Variables.COMPUTE_HASH,
|
| + elapsedTime);
|
| + }
|
| + if (chrome.runtime.lastError) {
|
| + reject(chrome.runtime.lastError);
|
| + } else {
|
| + resolve(result);
|
| + }
|
| + }.bind(this));
|
| + }.bind(this));
|
| +
|
| + this.hashCache_.put(cacheKey, hashPromise);
|
| + return hashPromise;
|
| + }.bind(this));
|
| };
|
|
|
| /**
|
| @@ -91,8 +113,9 @@ importer.DriveDuplicateFinder.prototype.computeHash_ = function(entry) {
|
| * @private
|
| */
|
| importer.DriveDuplicateFinder.prototype.findByHash_ = function(hash) {
|
| - return this.getDriveId_()
|
| - .then(this.searchFilesByHash_.bind(this, hash));
|
| + return /** @type {!Promise<Array<string>>} */ (
|
| + this.getDriveId_()
|
| + .then(this.searchFilesByHash_.bind(this, hash)));
|
| };
|
|
|
| /**
|
| @@ -119,7 +142,8 @@ importer.DriveDuplicateFinder.prototype.getDriveId_ = function() {
|
| * A promise-based wrapper for chrome.fileManagerPrivate.searchFilesByHashes.
|
| * @param {string} hash The content hash to search for.
|
| * @param {string} volumeId The volume to search.
|
| - * @return <!Promise<Array<string>>> A list of file URLs.
|
| + * @return {!Promise<Array<string>>} A list of file URLs.
|
| + * @private
|
| */
|
| importer.DriveDuplicateFinder.prototype.searchFilesByHash_ =
|
| function(hash, volumeId) {
|
|
|