diff options
Diffstat (limited to 'src/mongo/db/pipeline/accumulator_js_reduce.cpp')
| -rw-r--r-- | src/mongo/db/pipeline/accumulator_js_reduce.cpp | 82 |
1 files changed, 44 insertions, 38 deletions
diff --git a/src/mongo/db/pipeline/accumulator_js_reduce.cpp b/src/mongo/db/pipeline/accumulator_js_reduce.cpp index 71075978d6d..78058d5913d 100644 --- a/src/mongo/db/pipeline/accumulator_js_reduce.cpp +++ b/src/mongo/db/pipeline/accumulator_js_reduce.cpp @@ -32,6 +32,7 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/pipeline/accumulator_js_reduce.h" #include "mongo/db/pipeline/make_js_function.h" +#include "mongo/db/pipeline/map_reduce_options_gen.h" namespace mongo { @@ -120,47 +121,52 @@ Value AccumulatorInternalJsReduce::getValue(bool toBeMerged) { if (_values.size() < 1) { return Value{}; } - - const auto keySize = _key.getApproximateSize(); - Value result; - // Keep reducing until we have exactly one value. - while (true) { - BSONArrayBuilder bsonValues; - size_t numLeft = _values.size(); - for (; numLeft > 0; numLeft--) { - Value val = _values[numLeft - 1]; - - // Do not insert if doing so would exceed the the maximum allowed BSONObj size. - if (bsonValues.len() + keySize + val.getApproximateSize() > BSONObjMaxUserSize) { - // If we have reached the threshold for maximum allowed BSONObj size and only have a - // single value then no progress will be made on reduce. We must fail when this - // scenario is encountered. - size_t numNextReduce = _values.size() - numLeft; - uassert(31392, "Value too large to reduce", numNextReduce > 1); - break; + if (mrSingleReduceOptimizationEnabled && _values.size() == 1) { + // This optimization existed in the old Pre-4.4 MapReduce implementation. If the flag is + // set, then we should replicate the optimization. See SERVER-68766 for more details. + result = std::move(_values[0]); + } else { + const auto keySize = _key.getApproximateSize(); + + // Keep reducing until we have exactly one value. + while (true) { + BSONArrayBuilder bsonValues; + size_t numLeft = _values.size(); + for (; numLeft > 0; numLeft--) { + Value val = _values[numLeft - 1]; + + // Do not insert if doing so would exceed the the maximum allowed BSONObj size. + if (bsonValues.len() + keySize + val.getApproximateSize() > BSONObjMaxUserSize) { + // If we have reached the threshold for maximum allowed BSONObj size and only + // have a single value then no progress will be made on reduce. We must fail + // when this scenario is encountered. + size_t numNextReduce = _values.size() - numLeft; + uassert(31392, "Value too large to reduce", numNextReduce > 1); + break; + } + bsonValues << val; } - bsonValues << val; - } - auto expCtx = getExpressionContext(); - auto reduceFunc = makeJsFunc(expCtx, _funcSource); - - // Function signature: reduce(key, values). - BSONObj params = BSON_ARRAY(_key << bsonValues.arr()); - // For reduce, the key and values are both passed as 'params' so there's no need to set - // 'this'. - BSONObj thisObj; - Value reduceResult = - expCtx->getJsExecWithScope()->callFunction(reduceFunc, params, thisObj); - if (numLeft == 0) { - result = reduceResult; - break; - } else { - // Remove all values which have been reduced. - _values.resize(numLeft); - // Include most recent result in the set of values to be reduced. - _values.push_back(reduceResult); + auto expCtx = getExpressionContext(); + auto reduceFunc = makeJsFunc(expCtx, _funcSource); + + // Function signature: reduce(key, values). + BSONObj params = BSON_ARRAY(_key << bsonValues.arr()); + // For reduce, the key and values are both passed as 'params' so there's no need to set + // 'this'. + BSONObj thisObj; + Value reduceResult = + expCtx->getJsExecWithScope()->callFunction(reduceFunc, params, thisObj); + if (numLeft == 0) { + result = reduceResult; + break; + } else { + // Remove all values which have been reduced. + _values.resize(numLeft); + // Include most recent result in the set of values to be reduced. + _values.push_back(reduceResult); + } } } |
