|
|
@@ -83,51 +83,29 @@ proto.getSourceName = function getSourceName() {
|
|
|
* @method getNext
|
|
|
* @return {Object}
|
|
|
**/
|
|
|
-proto.getNext = function getNext(callback) {
|
|
|
- if (!callback) throw new Error(this.getSourceName() + " #getNext() requires callback.");
|
|
|
- if (this.expCtx.checkForInterrupt && this.expCtx.checkForInterrupt() === false)
|
|
|
- return callback(new Error("Interrupted"));
|
|
|
+proto.getNext = function getNext() {
|
|
|
+ if (this.expCtx && this.expCtx.checkForInterrupt) this.expCtx.checkForInterrupt();
|
|
|
|
|
|
- var self = this;
|
|
|
- async.series([
|
|
|
- function(next) {
|
|
|
- if (!self.populated)
|
|
|
- self.populate(function(err) {
|
|
|
- return next(err);
|
|
|
- });
|
|
|
- else
|
|
|
- return next();
|
|
|
- },
|
|
|
- function(next) {
|
|
|
- // NOTE: Skipped the spilled functionality
|
|
|
- if (self.spilled) {
|
|
|
- throw new Error("Spilled is not implemented.");
|
|
|
- } else {
|
|
|
- if(self.currentGroupsKeysIndex === self.groupsKeys.length) {
|
|
|
- return next(null, null);
|
|
|
- }
|
|
|
+ if (!this.populated)
|
|
|
+ this.populate();
|
|
|
|
|
|
- var out;
|
|
|
- try {
|
|
|
- var id = self.originalGroupsKeys[self.currentGroupsKeysIndex],
|
|
|
- stringifiedId = self.groupsKeys[self.currentGroupsKeysIndex],
|
|
|
- accumulators = self.groups[stringifiedId];
|
|
|
+ // NOTE: Skipped the spilled functionality
|
|
|
+ if (this.spilled) {
|
|
|
+ throw new Error("Spilled is not implemented.");
|
|
|
+ } else {
|
|
|
+ if (this.currentGroupsKeysIndex === this.groupsKeys.length)
|
|
|
+ return null;
|
|
|
|
|
|
- out = self.makeDocument(id, accumulators, self.expCtx.inShard);
|
|
|
+ var id = this.originalGroupsKeys[this.currentGroupsKeysIndex],
|
|
|
+ stringifiedId = this.groupsKeys[this.currentGroupsKeysIndex],
|
|
|
+ accumulators = this.groups[stringifiedId],
|
|
|
+ out = this.makeDocument(id, accumulators, this.expCtx.inShard);
|
|
|
|
|
|
- if(++self.currentGroupsKeysIndex === self.groupsKeys.length) {
|
|
|
- self.dispose();
|
|
|
- }
|
|
|
- } catch (ex) {
|
|
|
- return next(ex);
|
|
|
- }
|
|
|
+ if (++this.currentGroupsKeysIndex === this.groupsKeys.length)
|
|
|
+ this.dispose();
|
|
|
|
|
|
- return next(null, out);
|
|
|
- }
|
|
|
- }
|
|
|
- ], function(err, results) {
|
|
|
- callback(err, results[1]);
|
|
|
- });
|
|
|
+ return out;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
@@ -289,80 +267,67 @@ klass.createFromJson = function createFromJson(elem, expCtx) { //jshint maxcompl
|
|
|
* Populates the GroupDocumentSource by grouping all of the input documents at once.
|
|
|
*
|
|
|
* @method populate
|
|
|
- * @param callback {Function} Required. callback(err) when done populating.
|
|
|
* @async
|
|
|
**/
|
|
|
-proto.populate = function populate(callback) {
|
|
|
+proto.populate = function populate() {
|
|
|
var numAccumulators = this.accumulatorFactories.length;
|
|
|
- // NOTE: this is not in mongo, does it belong here?
|
|
|
- if(numAccumulators !== this.expressions.length) {
|
|
|
- callback(new Error("Must have equal number of accumulators and expressions"));
|
|
|
- }
|
|
|
+ if (numAccumulators !== this.expressions.length) throw new Error("dassert: Must have equal number of accumulators and expressions");
|
|
|
|
|
|
- var input,
|
|
|
- self = this;
|
|
|
- async.whilst(
|
|
|
- function() {
|
|
|
- return input !== null;
|
|
|
- },
|
|
|
- function(cb) {
|
|
|
- self.source.getNext(function(err, doc) {
|
|
|
- if(err) return cb(err);
|
|
|
- if(doc === null) {
|
|
|
- input = doc;
|
|
|
- return cb(); //Need to stop now, no new input
|
|
|
- }
|
|
|
- try {
|
|
|
- input = doc;
|
|
|
- self.variables.setRoot(input);
|
|
|
-
|
|
|
- /* get the _id value */
|
|
|
- var id = self.computeId(self.variables);
|
|
|
-
|
|
|
- if(undefined === id) id = null;
|
|
|
-
|
|
|
- var groupKey = JSON.stringify(id),
|
|
|
- group = self.groups[groupKey];
|
|
|
-
|
|
|
- if(!group) {
|
|
|
- self.originalGroupsKeys.push(id);
|
|
|
- self.groupsKeys.push(groupKey);
|
|
|
- group = [];
|
|
|
- self.groups[groupKey] = group;
|
|
|
- // Add the accumulators
|
|
|
- for(var afi = 0; afi<self.accumulatorFactories.length; afi++) {
|
|
|
- group.push(new self.accumulatorFactories[afi]());
|
|
|
- }
|
|
|
- }
|
|
|
- //NOTE: Skipped memory usage stuff for case when group already existed
|
|
|
+ // SKIPPED: DEVIATION FROM MONGO: spill and mem usage stuff
|
|
|
+ // pushed to on spill()
|
|
|
+ //var sortedFiles;
|
|
|
+ //int memoryUsageBytes = 0;
|
|
|
|
|
|
- if(numAccumulators !== group.length) {
|
|
|
- throw new Error("Group must have one of each accumulator");
|
|
|
- }
|
|
|
+ // This loop consumes all input from pSource and buckets it based on pIdExpression.
|
|
|
+ var input;
|
|
|
+ while ((input = this.source.getNext())) {
|
|
|
+ // SKIPPED: DEVIATION FROM MONGO: mem usage stuff
|
|
|
|
|
|
- //NOTE: passing the input to each accumulator
|
|
|
- for(var gi=0; gi<group.length; gi++) {
|
|
|
- group[gi].process(self.expressions[gi].evaluate(self.variables, self.doingMerge));
|
|
|
- }
|
|
|
+ this.variables.setRoot(input);
|
|
|
|
|
|
- // We are done with the ROOT document so release it.
|
|
|
- self.variables.clearRoot();
|
|
|
+ // get the _id value
|
|
|
+ var id = this.computeId(this.variables);
|
|
|
|
|
|
- //NOTE: Skipped the part about sorted files
|
|
|
- } catch (ex) {
|
|
|
- return cb(ex);
|
|
|
- }
|
|
|
- return cb();
|
|
|
- });
|
|
|
- },
|
|
|
- function(err) {
|
|
|
- if(err) return callback(err);
|
|
|
+ // treat missing values the same as NULL SERVER-4674
|
|
|
+ if (id === undefined)
|
|
|
+ id = null;
|
|
|
|
|
|
- self.populated = true;
|
|
|
+ // Look for the _id value in the map; if it's not there, add a
|
|
|
+ // new entry with a blank accumulator.
|
|
|
+ var groupKey = JSON.stringify(id),
|
|
|
+ group = this.groups[groupKey];
|
|
|
|
|
|
- return callback();
|
|
|
+ if (!group) {
|
|
|
+ this.originalGroupsKeys.push(id);
|
|
|
+ this.groupsKeys.push(groupKey);
|
|
|
+ group = [];
|
|
|
+ this.groups[groupKey] = group;
|
|
|
+
|
|
|
+ // Add the accumulators
|
|
|
+ for (var afi = 0, afl = this.accumulatorFactories.length; afi < afl; afi++) {
|
|
|
+ group.push(new this.accumulatorFactories[afi]());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // else {
|
|
|
+ // NOTE: Skipped memory usage stuff for case when group already existed
|
|
|
+ // }
|
|
|
+
|
|
|
+ // tickle all the accumulators for the group we found
|
|
|
+ if (numAccumulators !== group.length) throw new Error("Group must have one of each accumulator");
|
|
|
+ for (var gi = 0, gl = group.length; gi < gl; gi++) {
|
|
|
+ group[gi].process(this.expressions[gi].evaluate(this.variables, this.doingMerge));
|
|
|
}
|
|
|
- );
|
|
|
+
|
|
|
+ // We are done with the ROOT document so release it.
|
|
|
+ this.variables.clearRoot();
|
|
|
+
|
|
|
+ //NOTE: DEVIATION: skipped dev stuff
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //NOTE: DEVIATION: skipped the part about sorted files
|
|
|
+
|
|
|
+ this.populated = true;
|
|
|
};
|
|
|
|
|
|
/**
|