diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-11-20 13:57:09 -0500 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2017-11-20 13:57:09 -0500 |
commit | 015781fb73e66e99abcb2ceb998d22a79d915227 (patch) | |
tree | 01ab53ed7a365790ec70817aeb099bb65bc1dd7d | |
parent | 88b413760e2fa91b03267412c8d36a207975fd9e (diff) | |
download | mongo-015781fb73e66e99abcb2ceb998d22a79d915227.tar.gz |
SERVER-32005 IDL augment code with compiler likely macro
-rw-r--r-- | buildscripts/idl/idl/generator.py | 21 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.cpp | 31 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.h | 26 | ||||
-rw-r--r-- | src/mongo/idl/idl_test.cpp | 40 |
4 files changed, 91 insertions, 27 deletions
diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index 5c949134675..f48edb84f70 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -60,7 +60,7 @@ def _is_required_serializer_field(field): Fields that must be set before serialization are fields without default values, that are not optional, and are not chained. """ - return not field.ignore and not field.optional and not field.default and not field.chained + return not field.ignore and not field.optional and not field.default and not field.chained and not field.chained_struct_field def _get_field_constant_name(field): @@ -153,7 +153,8 @@ class _SlowFieldUsageChecker(_FieldUsageCheckerBase): def add_store(self, field_name): # type: (unicode) -> None self._writer.write_line('auto push_result = usedFields.insert(%s);' % (field_name)) - with writer.IndentedScopedBlock(self._writer, 'if (push_result.second == false) {', '}'): + with writer.IndentedScopedBlock(self._writer, + 'if (MONGO_unlikely(push_result.second == false)) {', '}'): self._writer.write_line('ctxt.throwDuplicateField(%s);' % (field_name)) def add(self, field, bson_element_variable): @@ -165,9 +166,9 @@ class _SlowFieldUsageChecker(_FieldUsageCheckerBase): # type: () -> None for field in self._fields: if (not field.optional) and (not field.ignore) and (not field.chained): - with writer.IndentedScopedBlock(self._writer, - 'if (usedFields.find(%s) == usedFields.end()) {' % - (_get_field_constant_name(field)), '}'): + pred = 'if (MONGO_unlikely(usedFields.find(%s) == usedFields.end())) {' % \ + (_get_field_constant_name(field)) + with writer.IndentedScopedBlock(self._writer, pred, '}'): if field.default: self._writer.write_line('%s = %s;' % (_get_field_member_name(field), field.default)) @@ -217,7 +218,7 @@ class _FastFieldUsageChecker(_FieldUsageCheckerBase): if not field in self._fields: self._fields.append(field) - with writer.IndentedScopedBlock(self._writer, 'if (usedFields[%s]) {' % + with writer.IndentedScopedBlock(self._writer, 'if (MONGO_unlikely(usedFields[%s])) {' % (_gen_field_usage_constant(field)), '}'): self._writer.write_line('ctxt.throwDuplicateField(%s);' % (bson_element_variable)) self._writer.write_empty_line() @@ -228,7 +229,8 @@ class _FastFieldUsageChecker(_FieldUsageCheckerBase): def add_final_checks(self): # type: () -> None """Output the code to check for missing fields.""" - with writer.IndentedScopedBlock(self._writer, 'if (!usedFields.all()) {', '}'): + with writer.IndentedScopedBlock(self._writer, 'if (MONGO_unlikely(!usedFields.all())) {', + '}'): for field in self._fields: if (not field.optional) and (not field.ignore): with writer.IndentedScopedBlock(self._writer, 'if (!usedFields[%s]) {' % @@ -788,7 +790,10 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_line('%s = %s;' % (_get_field_member_name(field), expression)) else: # May be an empty block if the type is 'any' - with self._predicate(_get_bson_type_check('element', 'ctxt', field)): + predicate = _get_bson_type_check('element', 'ctxt', field) + if predicate: + predicate = "MONGO_likely(%s)" % (predicate) + with self._predicate(predicate): object_value = self._gen_field_deserializer_expression('element', field) if field.chained_struct_field: self._writer.write_line('%s.%s(%s);' % diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp index 1de7730b780..888ea2894bd 100644 --- a/src/mongo/idl/idl_parser.cpp +++ b/src/mongo/idl/idl_parser.cpp @@ -63,29 +63,26 @@ std::string toCommaDelimitedList(const std::vector<BSONType>& types) { constexpr StringData IDLParserErrorContext::kOpMsgDollarDBDefault; constexpr StringData IDLParserErrorContext::kOpMsgDollarDB; -bool IDLParserErrorContext::checkAndAssertType(const BSONElement& element, BSONType type) const { +bool IDLParserErrorContext::checkAndAssertTypeSlowPath(const BSONElement& element, + BSONType type) const { auto elementType = element.type(); - if (elementType != type) { - // If the type is wrong, ignore Null and Undefined values - if (elementType == jstNULL || elementType == Undefined) { - return false; - } - - std::string path = getElementPath(element); - uasserted(ErrorCodes::TypeMismatch, - str::stream() << "BSON field '" << path << "' is the wrong type '" - << typeName(element.type()) - << "', expected type '" - << typeName(type) - << "'"); + // If the type is wrong, ignore Null and Undefined values + if (elementType == jstNULL || elementType == Undefined) { + return false; } - return true; + std::string path = getElementPath(element); + uasserted(ErrorCodes::TypeMismatch, + str::stream() << "BSON field '" << path << "' is the wrong type '" + << typeName(elementType) + << "', expected type '" + << typeName(type) + << "'"); } -bool IDLParserErrorContext::checkAndAssertBinDataType(const BSONElement& element, - BinDataType type) const { +bool IDLParserErrorContext::checkAndAssertBinDataTypeSlowPath(const BSONElement& element, + BinDataType type) const { bool isBinDataType = checkAndAssertType(element, BinData); if (!isBinDataType) { return false; diff --git a/src/mongo/idl/idl_parser.h b/src/mongo/idl/idl_parser.h index f5f6ba0f90e..fe3d614a255 100644 --- a/src/mongo/idl/idl_parser.h +++ b/src/mongo/idl/idl_parser.h @@ -72,7 +72,13 @@ public: * processed. * Throws an exception if the BSON element's type is wrong. */ - bool checkAndAssertType(const BSONElement& element, BSONType type) const; + bool checkAndAssertType(const BSONElement& element, BSONType type) const { + if (MONGO_likely(element.type() == type)) { + return true; + } + + return checkAndAssertTypeSlowPath(element, type); + } /** * Check that BSON element is a bin data type, and has the specified bin data subtype, or @@ -83,7 +89,13 @@ public: * processed. * Throws an exception if the BSON element's type is wrong. */ - bool checkAndAssertBinDataType(const BSONElement& element, BinDataType type) const; + bool checkAndAssertBinDataType(const BSONElement& element, BinDataType type) const { + if (MONGO_likely(element.type() == BinData && element.binDataType() == type)) { + return true; + } + + return checkAndAssertBinDataTypeSlowPath(element, type); + } /** * Check that BSON element is one of a given type or whether the field should be skipped. @@ -157,6 +169,16 @@ private: */ std::string getElementPath(StringData fieldName) const; + /** + * See comment on checkAndAssertType. + */ + bool checkAndAssertTypeSlowPath(const BSONElement& element, BSONType type) const; + + /** + * See comment on checkAndAssertBinDataType. + */ + bool checkAndAssertBinDataTypeSlowPath(const BSONElement& element, BinDataType type) const; + private: // Name of the current field that is being parsed. const StringData _currentField; diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp index 9723f802d46..1d3ac995b47 100644 --- a/src/mongo/idl/idl_test.cpp +++ b/src/mongo/idl/idl_test.cpp @@ -2172,5 +2172,45 @@ TEST(IDLCommand, TestKnownFieldDuplicate) { } +// Positive: Test an inline nested chain struct works +TEST(IDLChainedStruct, TestInline) { + IDLParserErrorContext ctxt("root"); + + auto testDoc = BSON("stringField" + << "bar" + << "field3" + << "foo"); + + auto testStruct = Chained_struct_inline::parse(ctxt, testDoc); + ASSERT_EQUALS(testStruct.getChained_string_inline_basic_type().getStringField(), "bar"); + ASSERT_EQUALS(testStruct.getField3(), "foo"); + + assert_same_types<decltype(testStruct.getChained_string_inline_basic_type().getStringField()), + const StringData>(); + assert_same_types<decltype(testStruct.getField3()), const StringData>(); + + // Positive: Test we can round trip to a document from the just parsed document + { + BSONObj loopbackDoc = testStruct.toBSON(); + + ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc); + } + + // Positive: Test we can serialize from nothing the same document + { + BSONObjBuilder builder; + Chained_struct_inline one_new; + one_new.setField3("foo"); + + Chained_string_inline_basic_type f1; + f1.setStringField("bar"); + one_new.setChained_string_inline_basic_type(f1); + + BSONObj loopbackDoc = one_new.toBSON(); + + ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc); + } +} + } // namespace } // namespace mongo |