diff options
author | Andrew Morrow <acm@10gen.com> | 2013-09-22 17:56:13 -0400 |
---|---|---|
committer | Andrew Morrow <acm@10gen.com> | 2013-09-25 14:21:49 -0400 |
commit | 03095b15c71886456ac46a315ea03614bb7aced4 (patch) | |
tree | e4298125ec6e9df0e6860c7721e53dbabbb18616 /src/mongo/bson/mutable | |
parent | 4616eae3efe8301ac12574bfc7c6d54338b58bd7 (diff) | |
download | mongo-03095b15c71886456ac46a315ea03614bb7aced4.tar.gz |
SERVER-10159 Improve the efficiency of constructing new ElementRep structures
Diffstat (limited to 'src/mongo/bson/mutable')
-rw-r--r-- | src/mongo/bson/mutable/document.cpp | 108 |
1 files changed, 57 insertions, 51 deletions
diff --git a/src/mongo/bson/mutable/document.cpp b/src/mongo/bson/mutable/document.cpp index c4f9c2e3739..b9c50aa20cb 100644 --- a/src/mongo/bson/mutable/document.cpp +++ b/src/mongo/bson/mutable/document.cpp @@ -492,23 +492,6 @@ namespace mutablebson { return offset; } - // For ElementRep to be a POD it can't have a constructor, so this will have to do. - ElementRep makeRep() { - ElementRep rep; - rep.objIdx = kInvalidObjIdx; - rep.serialized = false; - rep.array = false; - rep.reserved = 0; - rep.offset = 0; - rep.sibling.left = Element::kInvalidRepIdx; - rep.sibling.right = Element::kInvalidRepIdx; - rep.child.left = Element::kInvalidRepIdx; - rep.child.right = Element::kInvalidRepIdx; - rep.parent = Element::kInvalidRepIdx; - rep.pad = 0; - return rep; - } - // Returns true if this ElementRep is 'detached' from all other elements and can be // added as a child, which helps ensure that we maintain a tree rather than a graph // when adding new elements to the tree. The root element is never considered to be @@ -615,28 +598,44 @@ namespace mutablebson { return _slowElements[id - kFastReps]; } - // Insert the given ElementRep and return an ID for it. - Element::RepIdx insertElement(const ElementRep& rep) { - const Element::RepIdx id = _numElements++; - verify(id <= Element::kMaxRepIdx); + // Construct and return a new default initialized ElementRep. The RepIdx identifying + // the new rep is returned in the out parameter. + ElementRep& makeNewRep(Element::RepIdx* newIdx) { + + const ElementRep defaultRep = { + kInvalidObjIdx, + false, false, 0, + 0, + { Element::kInvalidRepIdx, Element::kInvalidRepIdx }, + { Element::kInvalidRepIdx, Element::kInvalidRepIdx }, + Element::kInvalidRepIdx, + 0 + }; + + const Element::RepIdx id = *newIdx = _numElements++; + if (id < kFastReps) { - _fastElements[id] = rep; + return _fastElements[id] = defaultRep; } else { - _slowElements.push_back(rep); + verify(id <= Element::kMaxRepIdx); + if (debug && paranoid) { // Force all reps to new addresses to help catch invalid rep usage. std::vector<ElementRep> newSlowElements(_slowElements); _slowElements.swap(newSlowElements); } + + return *_slowElements.insert(_slowElements.end(), defaultRep); } - return id; } // Insert a new ElementRep for a leaf element at the given offset and return its ID. Element::RepIdx insertLeafElement(int offset) { // BufBuilder hands back sizes in 'int's. - ElementRep rep = makeRep(); + Element::RepIdx inserted; + ElementRep& rep = makeNewRep(&inserted); + rep.objIdx = kLeafObjIdx; rep.serialized = true; dassert(offset >= 0); @@ -644,7 +643,7 @@ namespace mutablebson { dassert(static_cast<unsigned int>(offset) < std::numeric_limits<uint32_t>::max()); rep.offset = offset; _objects[kLeafObjIdx] = _leafBuilder.asTempObj(); - return insertElement(rep); + return inserted; } // Obtain the object builder for the leaves. @@ -766,7 +765,12 @@ namespace mutablebson { getObject(rep->objIdx)).firstElement(); if (!childElt.eoo()) { - ElementRep newRep = makeRep(); + Element::RepIdx inserted; + ElementRep& newRep = makeNewRep(&inserted); + // Calling makeNewRep invalidates rep since it may cause a reallocation of + // the element vector. After calling insertElement, we reacquire rep. + rep = &getElementRep(index); + newRep.serialized = true; newRep.objIdx = rep->objIdx; newRep.offset = @@ -778,11 +782,6 @@ namespace mutablebson { newRep.child.left = Element::kOpaqueRepIdx; newRep.child.right = Element::kOpaqueRepIdx; } - // Calling insertElement invalidates rep since insertElement may cause a - // reallocation of the element vector. After calling insertElement, we - // reacquire rep. - const Element::RepIdx inserted = insertElement(newRep); - rep = &getElementRep(index); rep->child.left = inserted; } else { rep->child.left = Element::kInvalidRepIdx; @@ -833,7 +832,12 @@ namespace mutablebson { BSONElement rightElt(elt.rawdata() + elt.size()); if (!rightElt.eoo()) { - ElementRep newRep = makeRep(); + Element::RepIdx inserted; + ElementRep& newRep = makeNewRep(&inserted); + // Calling makeNewRep invalidates rep since it may cause a reallocation of + // the element vector. After calling insertElement, we reacquire rep. + rep = &getElementRep(index); + newRep.serialized = true; newRep.objIdx = rep->objIdx; newRep.offset = @@ -846,11 +850,6 @@ namespace mutablebson { newRep.child.left = Element::kOpaqueRepIdx; newRep.child.right = Element::kOpaqueRepIdx; } - // Calling insertElement invalidates rep since insertElement may cause a - // reallocation of the element vector. After calling insertElement, we - // reacquire rep. - const Element::RepIdx inserted = insertElement(newRep); - rep = &getElementRep(index); rep->sibling.right = inserted; } else { rep->sibling.right = Element::kInvalidRepIdx; @@ -1938,7 +1937,7 @@ namespace mutablebson { thisRep = valueRep; // Be nice and clear out the source rep to make debugging easier. - valueRep = makeRep(); + valueRep = ElementRep(); impl.deserialize(thisRep.parent); return Status::OK(); @@ -2108,9 +2107,10 @@ namespace mutablebson { Impl& impl = getImpl(); dassert(impl.doesNotAlias(fieldName)); - ElementRep newElt = makeRep(); + Element::RepIdx newEltIdx; + ElementRep& newElt = impl.makeNewRep(&newEltIdx); impl.insertFieldName(newElt, fieldName); - return Element(this, impl.insertElement(newElt)); + return Element(this, newEltIdx); } Element Document::makeElementObject(const StringData& fieldName, const BSONObj& value) { @@ -2119,29 +2119,34 @@ namespace mutablebson { dassert(impl.doesNotAlias(value)); Element::RepIdx newEltIdx = Element::kInvalidRepIdx; + ElementRep* newElt = NULL; + // A cheap hack to detect that this Object Element is for the root. if (fieldName.rawData() == &kRootFieldName[0]) { - ElementRep newElt = makeRep(); + + newElt = &impl.makeNewRep(&newEltIdx); + // A BSONObj provided for the root Element is stored in _objects rather than being // copied like all other BSONObjs. - newElt.objIdx = impl.insertObject(value); - impl.insertFieldName(newElt, fieldName); + newElt->objIdx = impl.insertObject(value); + impl.insertFieldName(*newElt, fieldName); // Strictly, the following is a lie: the root isn't serialized, because it doesn't // have a contiguous fieldname. However, it is a useful fiction to pretend that it // is, so we can easily check if we have a 'pristine' document state by checking if // the root is marked as serialized. - newElt.serialized = true; - newEltIdx = impl.insertElement(newElt); + newElt->serialized = true; } else { // Copy the provided values into the leaf builder. BSONObjBuilder& builder = impl.leafBuilder(); const int leafRef = builder.len(); builder.append(fieldName, value); newEltIdx = impl.insertLeafElement(leafRef); + newElt = &impl.getElementRep(newEltIdx); } - ElementRep& newElt = impl.getElementRep(newEltIdx); - newElt.child.left = Element::kOpaqueRepIdx; - newElt.child.right = Element::kOpaqueRepIdx; + + newElt->child.left = Element::kOpaqueRepIdx; + newElt->child.right = Element::kOpaqueRepIdx; + return Element(this, newEltIdx); } @@ -2149,10 +2154,11 @@ namespace mutablebson { Impl& impl = getImpl(); dassert(impl.doesNotAlias(fieldName)); - ElementRep newElt = makeRep(); + Element::RepIdx newEltIdx; + ElementRep& newElt = impl.makeNewRep(&newEltIdx); newElt.array = true; impl.insertFieldName(newElt, fieldName); - return Element(this, impl.insertElement(newElt)); + return Element(this, newEltIdx); } Element Document::makeElementArray(const StringData& fieldName, const BSONObj& value) { |