Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / image_loader / scheduler.js
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6  * Scheduler for requests. Fetches requests from a queue and processes them
7  * synchronously, taking into account priorities. The highest priority is 0.
8  * @constructor
9  */
10 function Scheduler() {
11   /**
12    * List of requests waiting to be checked. If these items are available in
13    * cache, then they are processed immediately after starting the scheduler.
14    * However, if they have to be downloaded, then these requests are moved
15    * to pendingRequests_.
16    *
17    * @type {Array.<Request>}
18    * @private
19    */
20   this.newRequests_ = [];
21
22   /**
23    * List of pending requests for images to be downloaded.
24    * @type {Array.<Request>}
25    * @private
26    */
27   this.pendingRequests_ = [];
28
29   /**
30    * List of requests being processed.
31    * @type {Array.<Request>}
32    * @private
33    */
34   this.activeRequests_ = [];
35
36   /**
37    * Hash array of requests being added to the queue, but not finalized yet.
38    * @type {Object}
39    * @private
40    */
41   this.requests_ = {};
42
43   /**
44    * If the scheduler has been started.
45    * @type {boolean}
46    * @private
47    */
48   this.started_ = false;
49 }
50
51 /**
52  * Maximum download requests to be run in parallel.
53  * @type {number}
54  * @const
55  */
56 Scheduler.MAXIMUM_IN_PARALLEL = 5;
57
58 /**
59  * Adds a request to the internal priority queue and executes it when requests
60  * with higher priorities are finished. If the result is cached, then it is
61  * processed immediately once the scheduler is started.
62  *
63  * @param {Request} request Request object.
64  */
65 Scheduler.prototype.add = function(request) {
66   if (!this.started_) {
67     this.newRequests_.push(request);
68     this.requests_[request.getId()] = request;
69     return;
70   }
71
72   // Enqueue the request, since already started.
73   this.pendingRequests_.push(request);
74   this.sortPendingRequests_();
75
76   this.continue_();
77 };
78
79 /**
80  * Removes a request from the scheduler (if exists).
81  * @param {string} requestId Unique ID of the request.
82  */
83 Scheduler.prototype.remove = function(requestId) {
84   var request = this.requests_[requestId];
85   if (!request)
86     return;
87
88   // Remove from the internal queues with pending tasks.
89   var newIndex = this.pendingRequests_.indexOf(request);
90   if (newIndex != -1)
91     this.newRequests_.splice(newIndex, 1);
92   var pendingIndex = this.pendingRequests_.indexOf(request);
93   if (pendingIndex != -1)
94     this.pendingRequests_.splice(pendingIndex, 1);
95
96   // Cancel the request.
97   request.cancel();
98   delete this.requests_[requestId];
99 };
100
101 /**
102  * Starts handling requests.
103  */
104 Scheduler.prototype.start = function() {
105   this.started_ = true;
106
107   // Process tasks added before scheduler has been started.
108   this.pendingRequests_ = this.newRequests_;
109   this.sortPendingRequests_();
110   this.newRequests_ = [];
111
112   // Start serving enqueued requests.
113   this.continue_();
114 };
115
116 /**
117  * Sorts pending requests by priorities.
118  * @private
119  */
120 Scheduler.prototype.sortPendingRequests_ = function() {
121   this.pendingRequests_.sort(function(a, b) {
122     return a.getPriority() - b.getPriority();
123   });
124 };
125
126 /**
127  * Processes pending requests from the queue. There is no guarantee that
128  * all of the tasks will be processed at once.
129  *
130  * @private
131  */
132 Scheduler.prototype.continue_ = function() {
133   // Run only up to MAXIMUM_IN_PARALLEL in the same time.
134   while (this.pendingRequests_.length &&
135          this.activeRequests_.length < Scheduler.MAXIMUM_IN_PARALLEL) {
136     var request = this.pendingRequests_.shift();
137     this.activeRequests_.push(request);
138
139     // Try to load from cache. If doesn't exist, then download.
140     request.loadFromCacheAndProcess(
141         this.finish_.bind(this, request),
142         function(currentRequest) {
143           currentRequest.downloadAndProcess(
144               this.finish_.bind(this, currentRequest));
145         }.bind(this, request));
146   }
147 };
148
149 /**
150  * Handles finished requests.
151  *
152  * @param {Request} request Finished request.
153  * @private
154  */
155 Scheduler.prototype.finish_ = function(request) {
156   var index = this.activeRequests_.indexOf(request);
157   if (index < 0)
158     console.warn('Request not found.');
159   this.activeRequests_.splice(index, 1);
160   delete this.requests_[request.getId()];
161
162   // Continue handling the most important requests (if started).
163   if (this.started_)
164     this.continue_();
165 };