void bLSM::insertTuple(dataTuple *tuple) { if(log_mode && !recovering) { logUpdate(tuple); batch_size++; if(batch_size >= log_mode) { log_file->force_tail(log_file, LOG_FORCE_COMMIT); batch_size = 0; } } // Note, this is where we block for backpressure. Do this without holding // any locks! merge_mgr->read_tuple_from_small_component(0, tuple); dataTuple * pre_t = 0; // this is a pointer to any data tuples that we'll be deleting below. We need to update the merge_mgr statistics with it, but have to do so outside of the rb_mut region. pre_t = insertTupleHelper(tuple); if(pre_t) { // needs to be here; calls update_progress, which sometimes grabs mutexes.. merge_mgr->read_tuple_from_large_component(0, pre_t); // was interspersed with the erase, insert above... dataTuple::freetuple(pre_t); //free the previous tuple } DEBUG("tree size %d tuples %lld bytes.\n", tsize, tree_bytes); }
void bLSM::insertManyTuples(dataTuple ** tuples, int tuple_count) { for(int i = 0; i < tuple_count; i++) { merge_mgr->read_tuple_from_small_component(0, tuples[i]); } if(log_mode && !recovering) { for(int i = 0; i < tuple_count; i++) { logUpdate(tuples[i]); } batch_size ++; if(batch_size >= log_mode) { log_file->force_tail(log_file, LOG_FORCE_COMMIT); batch_size = 0; } } int num_old_tups = 0; pageid_t sum_old_tup_lens = 0; for(int i = 0; i < tuple_count; i++) { dataTuple * old_tup = insertTupleHelper(tuples[i]); if(old_tup) { num_old_tups++; sum_old_tup_lens += old_tup->byte_length(); dataTuple::freetuple(old_tup); } } merge_mgr->read_tuple_from_large_component(0, num_old_tups, sum_old_tup_lens); }
UpdateNode::ApplyResult ModifierNode::applyToNonexistentElement(ApplyParams applyParams) const { if (allowCreation()) { auto newElementFieldName = applyParams.pathToCreate->getPart(applyParams.pathToCreate->numParts() - 1); auto newElement = applyParams.element.getDocument().makeElementNull(newElementFieldName); setValueForNewElement(&newElement); invariant(newElement.ok()); auto statusWithFirstCreatedElem = pathsupport::createPathAt( *(applyParams.pathToCreate), 0, applyParams.element, newElement); if (!statusWithFirstCreatedElem.isOK()) { // $set operaions on non-viable paths are ignored when the update came from replication. // We do not error because idempotency requires that any other update modifiers must // still be applied. For example, consider applying the following updates twice to an // initially empty document: // {$set: {c: 0}} // {$set: {'a.b': 0, c: 1}} // {$set: {a: 0}} // Setting 'a.b' will fail the second time, but we must still set 'c'. // (There are modifiers besides $set that use this code path, but they are not used for // replication, so we are not concerned with their behavior when "fromReplication" is // true.) if (statusWithFirstCreatedElem.getStatus().code() == ErrorCodes::PathNotViable && applyParams.fromReplication) { return ApplyResult::noopResult(); } uassertStatusOK(statusWithFirstCreatedElem); MONGO_UNREACHABLE; // The previous uassertStatusOK should always throw. } if (applyParams.validateForStorage) { const uint32_t recursionLevel = applyParams.pathTaken->numParts() + 1; mutablebson::ConstElement elementForValidation = statusWithFirstCreatedElem.getValue(); validateUpdate(elementForValidation, elementForValidation.leftSibling(), elementForValidation.rightSibling(), recursionLevel, ModifyResult::kCreated); } for (auto immutablePath = applyParams.immutablePaths.begin(); immutablePath != applyParams.immutablePaths.end(); ++immutablePath) { // If 'immutablePath' is a (strict or non-strict) prefix of 'pathTaken', then we are // modifying 'immutablePath'. For example, adding '_id.x' will illegally modify '_id'. // (Note that this behavior is subtly different from checkImmutablePathsNotModified(), // because we just created this element.) uassert(ErrorCodes::ImmutableField, str::stream() << "Updating the path '" << applyParams.pathTaken->dottedField() << "' to " << applyParams.element.toString() << " would modify the immutable field '" << (*immutablePath)->dottedField() << "'", applyParams.pathTaken->commonPrefixSize(**immutablePath) != (*immutablePath)->numParts()); } invariant(!applyParams.pathToCreate->empty()); std::string fullPath; if (applyParams.pathTaken->empty()) { fullPath = applyParams.pathToCreate->dottedField().toString(); } else { fullPath = str::stream() << applyParams.pathTaken->dottedField() << "." << applyParams.pathToCreate->dottedField(); } ApplyResult applyResult; // Determine if indexes are affected. if (!applyParams.indexData || !applyParams.indexData->mightBeIndexed(fullPath)) { applyResult.indexesAffected = false; } if (applyParams.logBuilder) { logUpdate(applyParams.logBuilder, fullPath, newElement, ModifyResult::kCreated); } return applyResult; } else { // This path is for modifiers like $pop or $pull that generally have no effect when applied // to a path that does not exist. if (!allowNonViablePath()) { // One exception: some of these modifiers still fail when the nonexistent path is // "non-viable," meaning it couldn't be created even if we intended to. UpdateLeafNode::checkViability( applyParams.element, *(applyParams.pathToCreate), *(applyParams.pathTaken)); } return ApplyResult::noopResult(); } }
UpdateNode::ApplyResult ModifierNode::applyToExistingElement(ApplyParams applyParams) const { invariant(!applyParams.pathTaken->empty()); invariant(applyParams.pathToCreate->empty()); invariant(applyParams.element.ok()); mutablebson::ConstElement leftSibling = applyParams.element.leftSibling(); mutablebson::ConstElement rightSibling = applyParams.element.rightSibling(); bool compareWithOriginal = false; if (canSetObjectValue()) { for (auto immutablePath = applyParams.immutablePaths.begin(); immutablePath != applyParams.immutablePaths.end(); ++immutablePath) { if (applyParams.pathTaken->isPrefixOf(**immutablePath)) { compareWithOriginal = true; break; } } } // We have two different ways of checking for changes to immutable paths, depending on the style // of update. See the comments above checkImmutablePathsNotModifiedFromOriginal() and // checkImmutablePathsNotModified(). ModifyResult updateResult; if (compareWithOriginal) { BSONObj original = applyParams.element.getDocument().getObject(); updateResult = updateExistingElement(&applyParams.element, applyParams.pathTaken); if (updateResult == ModifyResult::kNoOp) { return ApplyResult::noopResult(); } checkImmutablePathsNotModifiedFromOriginal( applyParams.element, applyParams.pathTaken.get(), applyParams.immutablePaths, original); } else { updateResult = updateExistingElement(&applyParams.element, applyParams.pathTaken); if (updateResult == ModifyResult::kNoOp) { return ApplyResult::noopResult(); } checkImmutablePathsNotModified( applyParams.element, applyParams.pathTaken.get(), applyParams.immutablePaths); } invariant(updateResult != ModifyResult::kCreated); ApplyResult applyResult; if (!applyParams.indexData || !applyParams.indexData->mightBeIndexed(applyParams.pathTaken->dottedField())) { applyResult.indexesAffected = false; } if (applyParams.validateForStorage) { const uint32_t recursionLevel = applyParams.pathTaken->numParts(); validateUpdate( applyParams.element, leftSibling, rightSibling, recursionLevel, updateResult); } if (applyParams.logBuilder) { logUpdate(applyParams.logBuilder, applyParams.pathTaken->dottedField(), applyParams.element, updateResult); } return applyResult; }