summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2017-11-20 13:57:09 -0500
committerMark Benvenuto <mark.benvenuto@mongodb.com>2017-11-20 13:57:09 -0500
commit015781fb73e66e99abcb2ceb998d22a79d915227 (patch)
tree01ab53ed7a365790ec70817aeb099bb65bc1dd7d
parent88b413760e2fa91b03267412c8d36a207975fd9e (diff)
downloadmongo-015781fb73e66e99abcb2ceb998d22a79d915227.tar.gz
SERVER-32005 IDL augment code with compiler likely macro
-rw-r--r--buildscripts/idl/idl/generator.py21
-rw-r--r--src/mongo/idl/idl_parser.cpp31
-rw-r--r--src/mongo/idl/idl_parser.h26
-rw-r--r--src/mongo/idl/idl_test.cpp40
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