diff --git a/tools/buildmessage.js b/tools/buildmessage.js index 2c094af127..bbfcc3c776 100644 --- a/tools/buildmessage.js +++ b/tools/buildmessage.js @@ -195,10 +195,6 @@ var getCurrentProgressTracker = function () { return progress ? progress : rootProgress; }; -var nudge = function () { - getCurrentProgressTracker().nudge(); -}; - var addChildTracker = function (title) { var options = {}; options.title = title; @@ -586,6 +582,5 @@ _.extend(exports, { reportProgress: reportProgress, reportProgressDone: reportProgressDone, getCurrentProgressTracker: getCurrentProgressTracker, - addChildTracker: addChildTracker, - nudge: nudge + addChildTracker: addChildTracker }); diff --git a/tools/catalog.js b/tools/catalog.js index ce2601b78e..9288a67f32 100644 --- a/tools/catalog.js +++ b/tools/catalog.js @@ -311,20 +311,13 @@ _.extend(LayeredCatalog.prototype, { var self = this; var uniload = require('./uniload.js'); - var yielder = new utils.ThrottledYield(); - var constraintSolverPackage = uniload.load({ packages: [ 'constraint-solver'] })['constraint-solver']; self.resolver = new constraintSolverPackage.ConstraintSolver.PackagesResolver(self, { nudge: function () { - // This may be a singleton, but the resolver is in a package so it - // doesn't have access to it. - utils.Patience.nudge(); - buildmessage.nudge(); - - yielder.yield(); + Console.nudge(true); } }); }, diff --git a/tools/console.js b/tools/console.js index 81f73672f9..91bb6fca0a 100644 --- a/tools/console.js +++ b/tools/console.js @@ -23,6 +23,7 @@ var buildmessage = require('./buildmessage.js'); // XXX: Are we happy with chalk (and its sub-dependencies)? var chalk = require('chalk'); var cleanup = require('./cleanup.js'); +var utils = require('./utils.js'); PROGRESS_DEBUG = !!process.env.METEOR_PROGRESS_DEBUG; FORCE_PRETTY=undefined; @@ -135,6 +136,35 @@ _.extend(ProgressDisplayStatus.prototype, { } }); +//var spinner = ['-', '\\', '|', '/']; +//// I looked at some Unicode indeterminate progress indicators, such as: +//// +//// spinner = "▁▃▄▅▆▇▆▅▄▃".split(''); +//// spinner = "▉▊▋▌▍▎▏▎▍▌▋▊▉".split(''); +//// spinner = "▏▎▍▌▋▊▉▊▋▌▍▎▏▁▃▄▅▆▇▆▅▄▃".split(''); +//// spinner = "▉▊▋▌▍▎▏▎▍▌▋▊▉▇▆▅▄▃▁▃▄▅▆▇".split(''); +//// spinner = "⠉⠒⠤⣀⠤⠒".split(''); +//// +//// but none of them really seemed like an improvement. I think +//// the case for using unicode would be stronger in a determinate +//// progress indicator. +//// +//// There are also some four-frame options such as ◐◓◑◒ at +//// http://stackoverflow.com/a/2685827/157965 +//// but all of the ones I tried look terrible in the terminal. +//if (! self.quiet) { +// var animationFrame = 0; +// var printUpdate = fiberHelpers.bindEnvironment(function () { +// //runLog.logTemporary("=> Starting MongoDB... " + +// // spinner[animationFrame]); +// buildmessage.nudge(); +// animationFrame = (animationFrame + 1) % spinner.length; +// }); +// printUpdate(); +// var mongoProgressTimer = setInterval(printUpdate, 200); +//} + + var ProgressDisplayBar = function (console) { var self = this; @@ -285,7 +315,6 @@ _.extend(StatusPoller.prototype, { }); } } - }); var Console = function (options) { @@ -297,7 +326,9 @@ var Console = function (options) { self._progressDisplay = new ProgressDisplayNone(self); self._statusPoller = null; - self._lastStatusPoll = 0; + + self._throttledYield = new utils.ThrottledYield(); + self._throttledStatusPoll = new utils.Throttled(STATUS_INTERVAL_MS); self.verbose = false; @@ -382,18 +413,19 @@ _.extend(Console.prototype, { self.verbose = verbose; }, + // XXX: Move docs from Patience.nudge() // Like Patience.nudge(); this can be called during long lived operations // where the timer may be starved off the CPU. It will execute the poll if // it has been 'too long' - nudge: function () { + nudge: function (canYield) { var self = this; - var now = Date.now(); - if ((now - self._lastStatusPoll) < STATUS_INTERVAL_MS) { - return; + if (self._throttledStatusPoll.isAllowed()) { + if (self._statusPoller) { + self._statusPoller.statusPoll(); + } } - // XXX: TODO: Add canYield argument and yield? - if (self._statusPoller) { - self._statusPoller.statusPoll(); + if (canYield === true) { + self._throttledYield.yield(); } }, diff --git a/tools/progress.js b/tools/progress.js index c6fc3e056a..9eb4b3c68b 100644 --- a/tools/progress.js +++ b/tools/progress.js @@ -68,30 +68,6 @@ _.extend(Progress.prototype, { self.reportProgress(state); }, - // For when we don't have a clear idea how long something will take, - // (i.e. no end estimate), just call nudge occasionally. We'll build - // an exponential progress bar for the task. - nudge: function () { - var self = this; - - var halfLife = 25; - - var state = _.clone(self._selfState); - - if (!self._exponentialCounter) { - self._exponentialCounter = 1; - // Arbitrary endpoint - state.end = 100; - } else { - self._exponentialCounter++; - } - - var fractionLeft = Math.pow(0.5, self._exponentialCounter / halfLife); - state.current = state.end * (1 - fractionLeft); - - self.reportProgress(state); - }, - // Tries to determine which is the 'current' job in the tree // This is very heuristical... we use some hints, like: // don't descend into fork-join jobs; we know these execute concurrently, @@ -192,7 +168,7 @@ _.extend(Progress.prototype, { self._updateTotalState(); - console.Console.nudge(); + console.Console.nudge(false); self._notifyState(); }, diff --git a/tools/run-all.js b/tools/run-all.js index 71569bd135..6c45c0f8bc 100644 --- a/tools/run-all.js +++ b/tools/run-all.js @@ -143,40 +143,11 @@ _.extend(Runner.prototype, { } if (! self.stopped && self.mongoRunner) { - var spinner = ['-', '\\', '|', '/']; - // I looked at some Unicode indeterminate progress indicators, such as: - // - // spinner = "▁▃▄▅▆▇▆▅▄▃".split(''); - // spinner = "▉▊▋▌▍▎▏▎▍▌▋▊▉".split(''); - // spinner = "▏▎▍▌▋▊▉▊▋▌▍▎▏▁▃▄▅▆▇▆▅▄▃".split(''); - // spinner = "▉▊▋▌▍▎▏▎▍▌▋▊▉▇▆▅▄▃▁▃▄▅▆▇".split(''); - // spinner = "⠉⠒⠤⣀⠤⠒".split(''); - // - // but none of them really seemed like an improvement. I think - // the case for using unicode would be stronger in a determinate - // progress indicator. - // - // There are also some four-frame options such as ◐◓◑◒ at - // http://stackoverflow.com/a/2685827/157965 - // but all of the ones I tried look terrible in the terminal. - if (! self.quiet) { - var animationFrame = 0; - var printUpdate = fiberHelpers.bindEnvironment(function () { - //runLog.logTemporary("=> Starting MongoDB... " + - // spinner[animationFrame]); - buildmessage.nudge(); - animationFrame = (animationFrame + 1) % spinner.length; - }); - printUpdate(); - var mongoProgressTimer = setInterval(printUpdate, 200); - } - buildmessage.enterJob({ title: 'Starting MongoDB' }, function () { self.mongoRunner.start(); }); if (! self.quiet) { - clearInterval(mongoProgressTimer); if (! self.stopped) runLog.log("=> Started MongoDB."); } diff --git a/tools/utils.js b/tools/utils.js index d7b8a117b0..5cd5fcbc4a 100644 --- a/tools/utils.js +++ b/tools/utils.js @@ -576,6 +576,7 @@ exports.Patience = function (options) { } }; +// XXX: Remove var nextYield = null; var YIELD_EVERY_MS = 150; var ACTIVE_PATIENCES = {}; @@ -646,34 +647,48 @@ _.extend(exports.Patience.prototype, { } }); - -// This is a stripped down version of Patience, that just regulates the frequency of calling yield. -// It should behave similarly to calling yield on every iteration of a loop, -// except that it won't actually yield if there hasn't been a long enough time interval -// -// options: -// interval: minimum interval of time between yield calls -// (more frequent calls are simply dropped) -// -// XXX: Have Patience use ThrottledYield -exports.ThrottledYield = function (options) { +exports.Throttled = function (options) { var self = this; options = _.extend({ interval: 150 }, options || {}); self.interval = options.interval; var now = +(new Date); - // The next yield time is interval from now. - self.nextYield = now + self.interval; + self.next = now; +}; + +_.extend(exports.Throttled.prototype, { + isAllowed: function () { + var self = this; + var now = +(new Date); + + if (now < self.next) { + return false; + } + + self.next = now + self.interval; + return true; + } +}); + + +// ThrottledYield just regulates the frequency of calling yield. +// It should behave similarly to calling yield on every iteration of a loop, +// except that it won't actually yield if there hasn't been a long enough time interval +// +// options: +// interval: minimum interval of time between yield calls +// (more frequent calls are simply dropped) +exports.ThrottledYield = function (options) { + var self = this; + + self._throttle = new exports.Throttled(options); }; _.extend(exports.ThrottledYield.prototype, { yield: function () { var self = this; - var now = +(new Date); - - if (now >= self.nextYield) { - self.nextYield = now + self.interval; + if (self._throttle.isAllowed()) { utils.sleepMs(1); } }