summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Hernandez <scotthernandez@gmail.com>2013-12-20 12:44:40 -0500
committerScott Hernandez <scotthernandez@gmail.com>2013-12-20 14:16:08 -0500
commit191e9e47d8c211acdf7bef6850c261c2a40e2a8c (patch)
treeb5c4c627eb053ec283551ec8d2ad5f317dc25b8c
parent3b5b35c15690769df2a11a75a3c6e6afd7c2169a (diff)
downloadmongo-191e9e47d8c211acdf7bef6850c261c2a40e2a8c.tar.gz
SERVER-12126: Improve update validation performance
-rw-r--r--src/mongo/db/field_ref_set.cpp11
-rw-r--r--src/mongo/db/field_ref_set.h4
-rw-r--r--src/mongo/db/ops/update.cpp19
3 files changed, 25 insertions, 9 deletions
diff --git a/src/mongo/db/field_ref_set.cpp b/src/mongo/db/field_ref_set.cpp
index 64c5e178b7a..46b09e8dd4b 100644
--- a/src/mongo/db/field_ref_set.cpp
+++ b/src/mongo/db/field_ref_set.cpp
@@ -59,11 +59,12 @@ namespace mongo {
FieldRefSet::FieldRefSet() {
}
- void FieldRefSet::getConflicts(const FieldRef* toCheck, FieldRefSet* conflicts) const {
+ bool FieldRefSet::findConflicts(const FieldRef* toCheck, FieldRefSet* conflicts) const {
+ bool foundConflict = false;
// If the set is empty, there is no work to do.
if (_fieldSet.empty())
- return;
+ return foundConflict;
StringData prefixStr = safeFirstPart(toCheck);
FieldRef prefixField;
@@ -75,10 +76,16 @@ namespace mongo {
while (it != _fieldSet.end() && safeFirstPart(*it) == prefixStr) {
size_t common = (*it)->commonPrefixSize(*toCheck);
if ((*it)->numParts() == common || toCheck->numParts() == common) {
+ if (!conflicts)
+ return true;
+
conflicts->_fieldSet.insert(*it);
+ foundConflict = true;
}
++it;
}
+
+ return foundConflict;
}
void FieldRefSet::keepShortest(const FieldRef* toInsert) {
diff --git a/src/mongo/db/field_ref_set.h b/src/mongo/db/field_ref_set.h
index 71a48502739..e7258c2a184 100644
--- a/src/mongo/db/field_ref_set.h
+++ b/src/mongo/db/field_ref_set.h
@@ -94,8 +94,10 @@ namespace mongo {
/**
* Find all inserted fields which conflict with the FieldRef 'toCheck' by the semantics
* of 'insert', and add those fields to the 'conflicts' set.
+ *
+ * Return true if conflicts were found.
*/
- void getConflicts(const FieldRef* toCheck, FieldRefSet* conflicts) const;
+ bool findConflicts(const FieldRef* toCheck, FieldRefSet* conflicts) const;
void clear() {
_fieldSet.clear();
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 009a74a494f..6d0f3b3be7c 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -266,20 +266,27 @@ namespace mongo {
return s;
}
// Check if the updated field conflicts with immutable fields
- immutableFieldRef.getConflicts(&current, &changedImmutableFields);
+ immutableFieldRef.findConflicts(&current, &changedImmutableFields);
}
}
+ FieldRef idFR;
+ idFR.parse(idFieldName);
+ const bool idChanged = updatedFields.findConflicts(&idFR, NULL);
+
+ // Add _id to fields to check since it too is immutable
+ if (idChanged)
+ changedImmutableFields.keepShortest(&idFR);
+ else if (changedImmutableFields.empty()) {
+ // Return early if nothing changed which is immutable
+ return Status::OK();
+ }
+
LOG(4) << "Changed immutable fields: " << changedImmutableFields;
// 2.) Now compare values of the changed immutable fields (to make sure they haven't)
const mutablebson::ConstElement newIdElem = updated.root()[idFieldName];
- // Add _id to fields to check since it too is immutable
- FieldRef idFR;
- idFR.parse(idFieldName);
- changedImmutableFields.keepShortest(&idFR);
-
FieldRefSet::const_iterator where = changedImmutableFields.begin();
const FieldRefSet::const_iterator end = changedImmutableFields.end();
for( ; where != end; ++where ) {