diff options
author | Yoonsoo Kim <yoonsoo.kim@mongodb.com> | 2021-11-19 01:25:07 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-11-19 02:12:13 +0000 |
commit | a687be84420c5e8d7ad0ad565baef40b4726e654 (patch) | |
tree | fabe6a984979592f0cf7d36dad0cdf6b7b567005 /src/mongo/db/query/sbe_stage_builder_accumulator.cpp | |
parent | bbe3249b53c2452b6ad5afd87a5c36789954b3eb (diff) | |
download | mongo-a687be84420c5e8d7ad0ad565baef40b4726e654.tar.gz |
SERVER-61492 Support sharded $avg accumulator for SBE $group pushdown
Diffstat (limited to 'src/mongo/db/query/sbe_stage_builder_accumulator.cpp')
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_accumulator.cpp | 104 |
1 files changed, 77 insertions, 27 deletions
diff --git a/src/mongo/db/query/sbe_stage_builder_accumulator.cpp b/src/mongo/db/query/sbe_stage_builder_accumulator.cpp index fb2ed5134f6..35c274ef04c 100644 --- a/src/mongo/db/query/sbe_stage_builder_accumulator.cpp +++ b/src/mongo/db/query/sbe_stage_builder_accumulator.cpp @@ -158,7 +158,7 @@ std::pair<std::vector<std::unique_ptr<sbe::EExpression>>, EvalStage> buildAccumu makeBinaryOp(sbe::EPrimBinary::logicOr, generateNullOrMissing(input), generateNonNumericCheck(input)), - makeConstant(sbe::value::TypeTags::Nothing, 0), + makeConstant(sbe::value::TypeTags::NumberInt64, 0), makeConstant(sbe::value::TypeTags::NumberInt64, 1)); }, std::move(arg)); @@ -179,16 +179,65 @@ std::pair<std::unique_ptr<sbe::EExpression>, EvalStage> buildFinalizeAvg( str::stream() << "Expected two slots to finalize avg, got: " << aggSlots.size(), aggSlots.size() == 2); - // If we've encountered any numeric input, the counter would contain a positive integer. Unlike - // $sum, when there is no numeric input, $avg should return null. - auto finalizingExpression = sbe::makeE<sbe::EIf>( - generateNullOrMissing(aggSlots[1]), - makeConstant(sbe::value::TypeTags::Null, 0), - makeBinaryOp(sbe::EPrimBinary::div, - makeFunction("doubleDoubleSumFinalize", makeVariable(aggSlots[0])), - makeVariable(aggSlots[1]))); - - return {std::move(finalizingExpression), std::move(inputStage)}; + if (state.needsMerge) { + // To support the sharding behavior, the mongos splits $group into two separate $group + // stages one at the mongos-side and the other at the shard-side. This stage builder builds + // the shard-side plan. The shard-side $avg accumulator is responsible to return the partial + // avg in the form of {subTotal: val1, count: val2} when the type of sum is decimal or + // {subTotal: val1, count: val2, subTotalError: val3} when the type of sum is non-decimal. + auto sumResult = makeVariable(aggSlots[0]); + auto countResult = makeVariable(aggSlots[1]); + + // Existence of 'kDecimalTotal' element in the sum result means the type of sum result is + // decimal. + auto ifCondExpr = makeFunction( + "exists", + makeFunction("getElement", + sumResult->clone(), + makeConstant(sbe::value::TypeTags::NumberInt32, + static_cast<int>(sbe::vm::AggSumValueElems::kDecimalTotal)))); + // Returns {subTotal: val1, count: val2} if the type of the sum result is decimal. + auto thenExpr = makeNewObjFunction( + FieldPair{"subTotal"_sd, + // 'doubleDoubleSumFinalize' returns the sum, adding decimal + // sum and non-decimal sum. + makeFunction("doubleDoubleSumFinalize", sumResult->clone())}, + FieldPair{"count"_sd, countResult->clone()}); + // Returns {subTotal: val1, count: val2: subTotalError: val3} otherwise. + auto elseExpr = makeNewObjFunction( + FieldPair{ + "subTotal"_sd, + makeFunction("getElement", + sumResult->clone(), + makeConstant(sbe::value::TypeTags::NumberInt32, + static_cast<int>( + sbe::vm::AggSumValueElems::kNonDecimalTotalSum)))}, + FieldPair{"count"_sd, countResult->clone()}, + FieldPair{"subTotalError"_sd, + makeFunction( + "getElement", + sumResult->clone(), + makeConstant(sbe::value::TypeTags::NumberInt32, + static_cast<int>( + sbe::vm::AggSumValueElems::kNonDecimalTotalAddend)))}); + auto partialAvgFinalize = + sbe::makeE<sbe::EIf>(std::move(ifCondExpr), std::move(thenExpr), std::move(elseExpr)); + + return {std::move(partialAvgFinalize), std::move(inputStage)}; + } else { + // If we've encountered any numeric input, the counter would contain a positive integer. + // Unlike $sum, when there is no numeric input, $avg should return null. + auto finalizingExpression = sbe::makeE<sbe::EIf>( + makeBinaryOp(sbe::EPrimBinary::eq, + makeVariable(aggSlots[1]), + makeConstant(sbe::value::TypeTags::NumberInt64, 0)), + makeConstant(sbe::value::TypeTags::Null, 0), + makeBinaryOp(sbe::EPrimBinary::div, + makeFunction("doubleDoubleSumFinalize", makeVariable(aggSlots[0])), + makeVariable(aggSlots[1]))); + + return {std::move(finalizingExpression), std::move(inputStage)}; + } } std::pair<std::vector<std::unique_ptr<sbe::EExpression>>, EvalStage> buildAccumulatorSum( @@ -214,8 +263,8 @@ std::pair<std::unique_ptr<sbe::EExpression>, EvalStage> buildFinalizeSum( sumSlots.size() == 1); if (state.needsMerge) { - // When to support the sharding behavior, the mongos splits $group into two separate $group - // stages one at the mongo-side side and the other at the shard-side, the shard-side $sum + // To support the sharding behavior, the mongos splits $group into two separate $group + // stages one at the mongos-side and the other at the shard-side. The shard-side $sum // accumulator is responsible to return the partial sum which is mostly same format to the // global sum but in the cases of overflowed 'NumberInt32'/'NumberInt64', return a // sub-document {subTotal: val1, subTotalError: val2}. The builtin function for $sum @@ -228,20 +277,21 @@ std::pair<std::unique_ptr<sbe::EExpression>, EvalStage> buildFinalizeSum( [](sbe::EVariable input) { return sbe::makeE<sbe::EIf>( makeFunction("isArray", input.clone()), - makeFunction( - "newObj", - makeConstant("subTotal"_sd), - makeFunction( - "getElement", - input.clone(), - makeConstant(sbe::value::TypeTags::NumberInt32, - static_cast<int>(sbe::vm::AggPartialSumElems::kTotal))), - makeConstant("subTotalError"_sd), - makeFunction( - "getElement", - input.clone(), - makeConstant(sbe::value::TypeTags::NumberInt32, - static_cast<int>(sbe::vm::AggPartialSumElems::kError)))), + makeNewObjFunction( + FieldPair{ + "subTotal"_sd, + makeFunction("getElement", + input.clone(), + makeConstant(sbe::value::TypeTags::NumberInt32, + static_cast<int>( + sbe::vm::AggPartialSumElems::kTotal)))}, + FieldPair{ + "subTotalError"_sd, + makeFunction("getElement", + input.clone(), + makeConstant(sbe::value::TypeTags::NumberInt32, + static_cast<int>( + sbe::vm::AggPartialSumElems::kError)))}), input.clone()); }, std::move(sumFinalize)); |