summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/exec/filter.h2
-rw-r--r--src/mongo/db/field_ref.cpp75
-rw-r--r--src/mongo/db/field_ref.h25
-rw-r--r--src/mongo/db/field_ref_test.cpp1
-rw-r--r--src/mongo/db/matcher/path.cpp2
-rw-r--r--src/mongo/db/ops/modifier_rename.cpp6
6 files changed, 67 insertions, 44 deletions
diff --git a/src/mongo/db/exec/filter.h b/src/mongo/db/exec/filter.h
index 8eb05759d0a..ff9916bfb27 100644
--- a/src/mongo/db/exec/filter.h
+++ b/src/mongo/db/exec/filter.h
@@ -82,7 +82,7 @@ namespace mongo {
}
// This should not happen.
- massert(16920, "trying to match on unknown field: " + path->fieldRef().dottedField(),
+ massert(16920, "trying to match on unknown field: " + path->fieldRef().dottedField().toString(),
0);
return new SingleElementElementIterator(BSONElement());
diff --git a/src/mongo/db/field_ref.cpp b/src/mongo/db/field_ref.cpp
index 85d0c123fd9..15a1ed8c19f 100644
--- a/src/mongo/db/field_ref.cpp
+++ b/src/mongo/db/field_ref.cpp
@@ -108,6 +108,37 @@ namespace mongo {
return ++_size;
}
+ void FieldRef::reserialize() const {
+ std::string nextDotted;
+ // Reserve some space in the string. We know we will have, at minimum, a character for
+ // each component we are writing, and a dot for each component, less one. We don't want
+ // to reserve more, since we don't want to forfeit the SSO if it is applicable.
+ nextDotted.reserve((_size * 2) - 1);
+
+ // Concatenate the fields to a new string
+ for (size_t i = 0; i != _size; ++i) {
+ if (i > 0)
+ nextDotted.append(1, '.');
+ const StringData part = getPart(i);
+ nextDotted.append(part.rawData(), part.size());
+ }
+
+ // Make the new string our contents
+ _dotted.swap(nextDotted);
+
+ // Fixup the parts to refer to the new string
+ std::string::const_iterator where = _dotted.begin();
+ for (size_t i = 0; i != _size; ++i) {
+ StringData& part = (i < kReserveAhead) ? _fixed[i] : _variable[getIndex(i)];
+ const size_t size = part.size();
+ part = StringData(&*where, size);
+ where += (size + 1); // account for '.'
+ }
+
+ // Drop any replacements
+ _replacements.clear();
+ }
+
StringData FieldRef::getPart(size_t i) const {
dassert(i < _size);
@@ -152,25 +183,23 @@ namespace mongo {
return prefixSize;
}
- std::string FieldRef::dottedField( size_t offset ) const {
- std::string result;
+ StringData FieldRef::dottedField( size_t offset ) const {
+ if (_size == 0 || offset >= numParts() )
+ return StringData();
- if (_size == 0 || offset >= numParts() ) {
- // fall through, we will return the empty string.
- }
- else if (_replacements.empty() && (offset == 0)) {
- result = _dotted;
- }
- else {
- // Reserve some space in the string. We know we will have, at minimum, a character
- // for each component we are writing, and a dot for each component, less one.
- result.reserve(((_size - offset) * 2) - 1);
- for (size_t i=offset; i<_size; i++) {
- if ( i > offset )
- result.append(1, '.');
- StringData part = getPart(i);
- result.append(part.rawData(), part.size());
- }
+ if (!_replacements.empty())
+ reserialize();
+ dassert(_replacements.empty());
+
+ // Assume we want the whole thing
+ StringData result(_dotted);
+
+ // Strip off any leading parts we were asked to ignore
+ for (size_t i = 0; i < offset; ++i) {
+ const StringData part = getPart(i);
+ result = StringData(
+ result.rawData() + part.size() + 1,
+ result.size() - part.size() - 1);
}
return result;
@@ -231,16 +260,6 @@ namespace mongo {
_replacements.clear();
}
- size_t FieldRef::numReplaced() const {
- size_t res = 0;
- for (size_t i = 0; i < _replacements.size(); i++) {
- if (!_replacements[i].empty()) {
- res++;
- }
- }
- return res;
- }
-
std::ostream& operator<<(std::ostream& stream, const FieldRef& field) {
return stream << field.dottedField();
}
diff --git a/src/mongo/db/field_ref.h b/src/mongo/db/field_ref.h
index 681f9873932..06e60c2c165 100644
--- a/src/mongo/db/field_ref.h
+++ b/src/mongo/db/field_ref.h
@@ -90,7 +90,7 @@ namespace mongo {
* Returns a copy of the full dotted field in its current state (i.e., some parts may
* have been replaced since the parse() call).
*/
- std::string dottedField( size_t offset = 0 ) const;
+ StringData dottedField( size_t offsetFromStart = 0 ) const;
/**
* Compares the full dotted path represented by this FieldRef to other
@@ -117,12 +117,6 @@ namespace mongo {
*/
size_t numParts() const { return _size; }
- /**
- * Returns the number of fields parts that were replaced so far. Replacing the same
- * fields several times only counts for 1.
- */
- size_t numReplaced() const;
-
private:
// Dotted fields are most often not longer than four parts. We use a mixed structure
// here that will not require any extra memory allocation when that is the case. And
@@ -139,20 +133,29 @@ namespace mongo {
*/
size_t appendPart(const StringData& part);
+ /**
+ * Re-assemble _dotted from components, including any replacements in _replacements,
+ * and update the StringData components in _fixed and _variable to refer to the parts
+ * of the new _dotted. This is used to make the storage for the current value of this
+ * FieldRef contiguous so it can be returned as a StringData from the dottedField
+ * method above.
+ */
+ void reserialize() const;
+
// number of field parts stored
size_t _size;
// first kResevedAhead field components
- StringData _fixed[kReserveAhead];
+ mutable StringData _fixed[kReserveAhead];
// remaining field components
- std::vector<StringData> _variable;
+ mutable std::vector<StringData> _variable;
// cached dotted name
- std::string _dotted;
+ mutable std::string _dotted;
// back memory added with the setPart call pointed to by _fized and _variable
- std::vector<std::string> _replacements;
+ mutable std::vector<std::string> _replacements;
};
inline bool operator==(const FieldRef& lhs, const FieldRef& rhs) {
diff --git a/src/mongo/db/field_ref_test.cpp b/src/mongo/db/field_ref_test.cpp
index 1d98c76b2e3..67336b8ffea 100644
--- a/src/mongo/db/field_ref_test.cpp
+++ b/src/mongo/db/field_ref_test.cpp
@@ -147,7 +147,6 @@ namespace {
fieldRef.setPart(1, parts[i]);
ASSERT_EQUALS(fieldRef.dottedField(), prefix + parts[i]);
}
- ASSERT_EQUALS(fieldRef.numReplaced(), 1U);
}
TEST( Prefix, Normal ) {
diff --git a/src/mongo/db/matcher/path.cpp b/src/mongo/db/matcher/path.cpp
index 8c94514ca63..cd4f1ee9c0a 100644
--- a/src/mongo/db/matcher/path.cpp
+++ b/src/mongo/db/matcher/path.cpp
@@ -110,7 +110,7 @@ namespace mongo {
void BSONElementIterator::ArrayIterationState::reset( const FieldRef& ref, int start ) {
- restOfPath = ref.dottedField( start );
+ restOfPath = ref.dottedField( start ).toString();
hasMore = restOfPath.size() > 0;
if ( hasMore ) {
nextPieceOfPath = ref.getPart( start );
diff --git a/src/mongo/db/ops/modifier_rename.cpp b/src/mongo/db/ops/modifier_rename.cpp
index f9505de53cc..cb7d2875afe 100644
--- a/src/mongo/db/ops/modifier_rename.cpp
+++ b/src/mongo/db/ops/modifier_rename.cpp
@@ -253,8 +253,10 @@ namespace mongo {
dassert(_preparedState->applyCalled);
const bool isPrefix = _fromFieldRef.isPrefixOf(_toFieldRef);
- const string setPath = (isPrefix ? _fromFieldRef : _toFieldRef).dottedField();
- const string unsetPath = isPrefix ? "" : _fromFieldRef.dottedField();
+ const StringData setPath =
+ (isPrefix ? _fromFieldRef : _toFieldRef).dottedField();
+ const StringData unsetPath =
+ isPrefix ? StringData() : _fromFieldRef.dottedField();
const bool doUnset = !isPrefix;
// We'd like to create an entry such as {$set: {<fieldname>: <value>}} under 'logRoot'.