diff --git a/ui/TODO.otl b/ui/TODO.otl index 14d0f714..9cff4896 100755 --- a/ui/TODO.otl +++ b/ui/TODO.otl @@ -562,6 +562,17 @@ Roadmap | drops to last placeholder | [_] single image mode transition (alpha-blend/fade/none) + [X] BUG: deferredPool breaks on exporting previews and a preview exists... + | export in place (default settings) runs through an initial set of + | workers and stops in an odd state: + | - pool is full + | - al workers resolved + | + | this appears to be the result of exportImageTo(..) not overwriting + | a preview... + [X] BUG: export: if lots of images already exist, the pool triggers depleted early... + | this happens if we are clearing the pool out faster than adding + | new tasks to queue... [X] buildcache: add ability to process multiple dirs... [X] BUG: progress bars do not handle errors... [X] BUG: sorting (dialog) will mess up the order... diff --git a/ui/files.js b/ui/files.js index a841e04d..f0fdf816 100755 --- a/ui/files.js +++ b/ui/files.js @@ -987,7 +987,6 @@ function exportImageTo(gid, path, im_name, size){ dest = path +'/'+ dest // copy... - // NOTE: the sad smily face here is here for JS compatibility ;) return (function(src, dest){ return copyFile(src, dest) .done(function(){ @@ -1038,6 +1037,8 @@ function exportImagesTo(path, im_name, dir_name, size){ res.resolve() }) + pool.filling() + // go through ribbons... for(var i=DATA.ribbons.length-1; i >= 0; i--){ var ribbon = DATA.ribbons[i] @@ -1060,6 +1061,8 @@ function exportImagesTo(path, im_name, dir_name, size){ path = normalizePath(path +'/'+ dir_name) } + pool.doneFilling() + return res } diff --git a/ui/lib/jli.js b/ui/lib/jli.js index f0968df9..c4f80a90 100755 --- a/ui/lib/jli.js +++ b/ui/lib/jli.js @@ -668,6 +668,19 @@ jQuery.fn.sortChildren = function(func){ // // This will create and return a pooled queue of deferred workers. // +// +// The pool can be in one of the folowing states: +// +// - filling +// This state prevents .depleted() from triggering until the pool +// exits the filling state. +// This helps us to prevent premature depletion of the pool in +// cases where the queue is depleted faster than it is being filled. +// +// - paused +// This state prevents any new queued workers from starting. +// +// // Public interface: // // .enqueue(obj, func, args) -> deferred @@ -677,6 +690,20 @@ jQuery.fn.sortChildren = function(func){ // If the pool is full the worker is added to queue (FIFO) and // ran in its turn. // +// .dropQueue() -> pool +// Drop the queued workers. +// NOTE: this will not stop the already running workers. +// +// +// .filling() +// Enter the filling state +// +// .doneFilling() +// Exit the filling state +// NOTE: this will trigger .depleted() if at the time of call +// both the pool and queue are empty. +// +// // .pause() -> pool // Pause the queue. // NOTE: this also has a second form: .pause(func), see below. @@ -684,9 +711,9 @@ jQuery.fn.sortChildren = function(func){ // .resume() -> pool // Restart the queue. // -// .dropQueue() -> pool -// Drop the queued workers. -// NOTE: this will not stop the already running workers. +// +// .isFilling() -> bool +// Test if the pool is being filled -- filling state. // // .isRunning() -> bool // Test if any workers are running in the pool. @@ -792,9 +819,15 @@ function makeDeferredPool(size, paused){ // run an element from the queue... var worker = func.apply(null, args) + pool.push(worker) + + // NOTE: this is explicitly after the pool push to avoid the + // possible race condition of the worker exiting and + // triggering .always(..) before being added to the pool... + worker .always(function(){ // prepare to remove self from pool... - var i = pool.indexOf(worker) + var i = pool.indexOf(this) Pool._event_handlers.progress.fire(pool.length - pool.len(), pool.length + queue.length) @@ -830,7 +863,9 @@ function makeDeferredPool(size, paused){ // pushed to pool just before it's "compacted"... pool.length = 0 - that._event_handlers.deplete.fire(l) + if(!that._filling){ + that._event_handlers.deplete.fire(l) + } } // keep the pool full... @@ -847,8 +882,6 @@ function makeDeferredPool(size, paused){ deferred.resolve.apply(deferred, arguments) }) - this.pool.push(worker) - return worker } @@ -899,6 +932,31 @@ function makeDeferredPool(size, paused){ return this } + // Filling state... + // + // When this mode is set, it will prevent the queue from triggering + // the depleated action until .doneFilling() is called... + // + // This is to prevent the pool depleting before the queue is filled + // in the case of tasks ending faster than they are added... + Pool.filling = function(){ + this._filling = true + return this + } + Pool.doneFilling = function(){ + delete this._filling + // trigger depleted if we are empty... + if(this.pool.len() == 0 && this.queue.length == 0){ + that._event_handlers.deplete.fire(l) + } + return this + } + Pool.isFilling = function(){ + return this._filling == true + } + + // Paused state... + // // NOTE: this will not directly cause .isRunning() to return false // as this will not directly spot all workers, it will just // pause the queue and the workers that have already started