Skip to content

Commit 40c8c6e

Browse files
kauboy26Evergreen Agent
authored andcommitted
SERVER-82832 Stop creating and destroying vectors unnecessarily in checkAndAssertTypes
1 parent 7ecd6bd commit 40c8c6e

File tree

4 files changed

+48
-22
lines changed

4 files changed

+48
-22
lines changed

buildscripts/idl/idl/generator.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,18 @@ def _access_member(field):
107107
return member_name
108108

109109

110+
def _std_array_expr(value_type, elems):
111+
# type: (str, List[str]) -> str
112+
"""Return a std::array<value_type, N>{elems} expression."""
113+
elem_str = ', '.join(elems)
114+
return f'std::array<{value_type}, {len(elems)}>{{{elem_str}}}'
115+
116+
110117
def _get_bson_type_check(bson_element, ctxt_name, ast_type):
111118
# type: (str, str, ast.Type) -> str
112119
"""Get the C++ bson type check for a Type."""
113-
bson_types = ast_type.bson_serialization_type
120+
# Deduplicate the types in the array.
121+
bson_types = list(set(ast_type.bson_serialization_type))
114122
if len(bson_types) == 1:
115123
if bson_types[0] in ['any', 'chain']:
116124
# Skip BSON validation for 'any' types since they are required to validate the
@@ -120,13 +128,14 @@ def _get_bson_type_check(bson_element, ctxt_name, ast_type):
120128
return None
121129

122130
if not bson_types[0] == 'bindata':
123-
return '%s.checkAndAssertType(%s, %s)' % (ctxt_name, bson_element,
124-
bson.cpp_bson_type_name(bson_types[0]))
125-
return '%s.checkAndAssertBinDataType(%s, %s)' % (
131+
return 'MONGO_likely(%s.checkAndAssertType(%s, %s))' % (
132+
ctxt_name, bson_element, bson.cpp_bson_type_name(bson_types[0]))
133+
return 'MONGO_likely(%s.checkAndAssertBinDataType(%s, %s))' % (
126134
ctxt_name, bson_element, bson.cpp_bindata_subtype_type_name(ast_type.bindata_subtype))
127135
else:
128-
type_list = '{%s}' % (', '.join([bson.cpp_bson_type_name(b) for b in bson_types]))
129-
return '%s.checkAndAssertTypes(%s, %s)' % (ctxt_name, bson_element, type_list)
136+
return (
137+
f'MONGO_likely({ctxt_name}.checkAndAssertTypes({bson_element}, '
138+
f'{_std_array_expr("BSONType", [bson.cpp_bson_type_name(b) for b in bson_types])}))')
130139

131140

132141
def _get_required_fields(struct):
@@ -1383,7 +1392,6 @@ def _gen_array_deserializer(self, field, bson_element, ast_type, tenant):
13831392

13841393
with self._predicate('MONGO_likely(arrayFieldName == expectedFieldNumber)'):
13851394
check = _get_bson_type_check('arrayElement', 'arrayCtxt', ast_type)
1386-
check = "MONGO_likely(%s)" % (check) if check is not None else check
13871395

13881396
with self._predicate(check):
13891397
if ast_type.is_variant:
@@ -1456,11 +1464,12 @@ def _gen_variant_deserializer(self, field, bson_element, tenant):
14561464

14571465
self._writer.write_line('default:')
14581466
self._writer.indent()
1459-
expected_types = ', '.join(
1460-
'BSONType::%s' % bson.cpp_bson_type_name(t.bson_serialization_type[0])
1461-
for t in array_types)
1467+
expected_types = [
1468+
bson.cpp_bson_type_name(t.bson_serialization_type[0]) for t in array_types
1469+
]
14621470
self._writer.write_line(
1463-
'ctxt.throwBadType(%s, {%s});' % (bson_element, expected_types))
1471+
f'ctxt.throwBadType({bson_element}, {_std_array_expr("BSONType", expected_types)});'
1472+
)
14641473
self._writer.write_line('break;')
14651474
self._writer.unindent()
14661475
# End of inner switch.
@@ -1497,10 +1506,11 @@ def _gen_variant_deserializer(self, field, bson_element, tenant):
14971506

14981507
self._writer.write_line('default:')
14991508
self._writer.indent()
1500-
expected_types = ', '.join(
1501-
'BSONType::%s' % bson.cpp_bson_type_name(t.bson_serialization_type[0])
1502-
for t in scalar_types)
1503-
self._writer.write_line('ctxt.throwBadType(%s, {%s});' % (bson_element, expected_types))
1509+
expected_types = [
1510+
bson.cpp_bson_type_name(t.bson_serialization_type[0]) for t in array_types
1511+
]
1512+
self._writer.write_line(f'ctxt.throwBadType({bson_element}, '
1513+
f'{_std_array_expr("BSONType", expected_types)});')
15041514
self._writer.write_line('break;')
15051515
self._writer.unindent()
15061516

@@ -1615,8 +1625,6 @@ def validate_and_assign_or_uassert(field, expression):
16151625
predicate = None
16161626
if check_type:
16171627
predicate = _get_bson_type_check(bson_element, 'ctxt', field_type)
1618-
if predicate:
1619-
predicate = "MONGO_likely(%s)" % (predicate)
16201628

16211629
with self._predicate(predicate):
16221630

src/mongo/idl/idl_parser.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <cstddef>
3434
#include <cstdint>
3535
#include <iterator>
36+
#include <span>
3637
#include <stack>
3738
#include <string>
3839

@@ -50,7 +51,7 @@ namespace {
5051
*
5152
* Example: "string, bool, numberDouble"
5253
*/
53-
std::string toCommaDelimitedList(const std::vector<BSONType>& types) {
54+
std::string toCommaDelimitedList(std::span<const BSONType> types) {
5455
str::stream builder;
5556

5657
for (std::size_t i = 0; i < types.size(); ++i) {
@@ -104,7 +105,7 @@ bool IDLParserContext::checkAndAssertBinDataTypeSlowPath(const BSONElement& elem
104105
}
105106

106107
bool IDLParserContext::checkAndAssertTypes(const BSONElement& element,
107-
const std::vector<BSONType>& types) const {
108+
std::span<const BSONType> types) const {
108109
auto elementType = element.type();
109110

110111
auto pos = std::find(types.begin(), types.end(), elementType);
@@ -220,7 +221,7 @@ void IDLParserContext::throwBadEnumValue(StringData enumValue) const {
220221
}
221222

222223
void IDLParserContext::throwBadType(const BSONElement& element,
223-
const std::vector<BSONType>& types) const {
224+
std::span<const BSONType> types) const {
224225
std::string path = getElementPath(element);
225226
std::string type_str = toCommaDelimitedList(types);
226227
uasserted(ErrorCodes::TypeMismatch,

src/mongo/idl/idl_parser.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <boost/optional.hpp>
3535
#include <boost/optional/optional.hpp>
3636
#include <cstdint>
37+
#include <span>
3738
#include <string>
3839
#include <type_traits>
3940
#include <utility>
@@ -359,7 +360,7 @@ class IDLParserContext {
359360
* processed.
360361
* Throws an exception if the BSON element's type is wrong.
361362
*/
362-
bool checkAndAssertTypes(const BSONElement& element, const std::vector<BSONType>& types) const;
363+
bool checkAndAssertTypes(const BSONElement& element, std::span<const BSONType> types) const;
363364

364365
/**
365366
* Throw an error message about the BSONElement being a duplicate field.
@@ -397,7 +398,7 @@ class IDLParserContext {
397398
* Throw an error about a field having the wrong type.
398399
*/
399400
MONGO_COMPILER_NORETURN void throwBadType(const BSONElement& element,
400-
const std::vector<BSONType>& types) const;
401+
std::span<const BSONType> types) const;
401402

402403
/**
403404
* Throw an 'APIStrictError' if the user command has 'apiStrict' field as true.

src/mongo/idl/idl_parser_bm.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,5 +317,21 @@ void BM_ARRAY_BSON(benchmark::State& state) {
317317

318318
BENCHMARK(BM_ARRAY_BSON)->Arg(10)->Arg(1000)->Arg(10000)->Unit(benchmark::kNanosecond);
319319

320+
void BM_CHECK_AND_ASSERT_TYPES(benchmark::State& state) {
321+
// Perform setup here.
322+
// We construct a WriteCommandRequestBase with just the "bypassDocumentValidation"
323+
// field set, which is of type safeBool, to run the generated checkAndAssertTypes()
324+
// function.
325+
auto request = BSON("bypassDocumentValidation" << 1);
326+
327+
for (auto _ : state) {
328+
// This code gets timed
329+
benchmark::DoNotOptimize(
330+
write_ops::WriteCommandRequestBase::parse(IDLParserContext("test"), request));
331+
}
332+
}
333+
334+
BENCHMARK(BM_CHECK_AND_ASSERT_TYPES);
335+
320336
} // namespace
321337
} // namespace mongo

0 commit comments

Comments
 (0)