From 191e9e47d8c211acdf7bef6850c261c2a40e2a8c Mon Sep 17 00:00:00 2001 From: Scott Hernandez Date: Fri, 20 Dec 2013 12:44:40 -0500 Subject: SERVER-12126: Improve update validation performance --- src/mongo/db/field_ref_set.cpp | 11 +++++++++-- src/mongo/db/field_ref_set.h | 4 +++- src/mongo/db/ops/update.cpp | 19 +++++++++++++------ 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(¤t, &changedImmutableFields); + immutableFieldRef.findConflicts(¤t, &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 ) { -- cgit v1.2.1