bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { BSONElement first = cmdObj.firstElement(); uassert(28528, str::stream() << "Argument to listIndexes must be of type String, not " << typeName(first.type()), first.type() == String); StringData collectionName = first.valueStringData(); uassert(28529, str::stream() << "Argument to listIndexes must be a collection name, " << "not the empty string", !collectionName.empty()); const NamespaceString ns(dbname, collectionName); const long long defaultBatchSize = std::numeric_limits<long long>::max(); long long batchSize; Status parseCursorStatus = parseCommandCursorOptions(cmdObj, defaultBatchSize, &batchSize); if (!parseCursorStatus.isOK()) { return appendCommandStatus(result, parseCursorStatus); } AutoGetCollectionForRead autoColl(txn, ns); if (!autoColl.getDb()) { return appendCommandStatus(result, Status(ErrorCodes::NamespaceNotFound, "no database")); } const Collection* collection = autoColl.getCollection(); if (!collection) { return appendCommandStatus(result, Status(ErrorCodes::NamespaceNotFound, "no collection")); } const CollectionCatalogEntry* cce = collection->getCatalogEntry(); invariant(cce); vector<string> indexNames; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { indexNames.clear(); cce->getAllIndexes(txn, &indexNames); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "listIndexes", ns.ns()); auto ws = make_unique<WorkingSet>(); auto root = make_unique<QueuedDataStage>(txn, ws.get()); for (size_t i = 0; i < indexNames.size(); i++) { BSONObj indexSpec; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { indexSpec = cce->getIndexSpec(txn, indexNames[i]); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "listIndexes", ns.ns()); WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); member->keyData.clear(); member->loc = RecordId(); member->obj = Snapshotted<BSONObj>(SnapshotId(), indexSpec.getOwned()); member->transitionToOwnedObj(); root->pushBack(id); } std::string cursorNamespace = str::stream() << dbname << ".$cmd." << name << "." << ns.coll(); dassert(NamespaceString(cursorNamespace).isValid()); dassert(NamespaceString(cursorNamespace).isListIndexesCursorNS()); dassert(ns == NamespaceString(cursorNamespace).getTargetNSForListIndexes()); auto statusWithPlanExecutor = PlanExecutor::make( txn, std::move(ws), std::move(root), cursorNamespace, PlanExecutor::YIELD_MANUAL); if (!statusWithPlanExecutor.isOK()) { return appendCommandStatus(result, statusWithPlanExecutor.getStatus()); } unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue()); BSONArrayBuilder firstBatch; const int byteLimit = FindCommon::kMaxBytesToReturnToClientAtOnce; for (long long objCount = 0; objCount < batchSize && firstBatch.len() < byteLimit; objCount++) { BSONObj next; PlanExecutor::ExecState state = exec->getNext(&next, NULL); if (state == PlanExecutor::IS_EOF) { break; } invariant(state == PlanExecutor::ADVANCED); firstBatch.append(next); } CursorId cursorId = 0LL; if (!exec->isEOF()) { exec->saveState(); exec->detachFromOperationContext(); ClientCursor* cursor = new ClientCursor(CursorManager::getGlobalCursorManager(), exec.release(), cursorNamespace, txn->recoveryUnit()->isReadingFromMajorityCommittedSnapshot()); cursorId = cursor->cursorid(); } appendCursorResponseObject(cursorId, cursorNamespace, firstBatch.arr(), &result); return true; }
int versionCmp(StringData rhs, StringData lhs) { if (strcmp(rhs.data(),lhs.data()) == 0) return 0; // handle "1.2.3-" and "1.2.3-pre" if (rhs.size() < lhs.size()) { if (strncmp(rhs.data(), lhs.data(), rhs.size()) == 0 && lhs.data()[rhs.size()] == '-') return +1; } else if (rhs.size() > lhs.size()) { if (strncmp(rhs.data(), lhs.data(), lhs.size()) == 0 && rhs.data()[lhs.size()] == '-') return -1; } return lexNumCmp(rhs.data(), lhs.data()); }
void UpdateIndexData::addPathComponent(StringData pathComponent) { _pathComponents.insert(pathComponent.toString()); }
Status HostAndPort::initialize(const StringData& s) { size_t colonPos = s.rfind(':'); StringData hostPart = s.substr(0, colonPos); // handle ipv6 hostPart (which we require to be wrapped in []s) const size_t openBracketPos = s.find('['); const size_t closeBracketPos = s.find(']'); if (openBracketPos != std::string::npos) { if (openBracketPos != 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "'[' present, but not first character in " << s.toString()); } if (closeBracketPos == std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "ipv6 address is missing closing ']' in hostname in " << s.toString()); } hostPart = s.substr(openBracketPos+1, closeBracketPos-openBracketPos-1); // prevent accidental assignment of port to the value of the final portion of hostPart if (colonPos < closeBracketPos) { colonPos = std::string::npos; } else if (colonPos != closeBracketPos+1) { return Status(ErrorCodes::FailedToParse, str::stream() << "Extraneous characters between ']' and pre-port ':'" << " in " << s.toString()); } } else if (closeBracketPos != std::string::npos) { return Status(ErrorCodes::FailedToParse, str::stream() << "']' present without '[' in " << s.toString()); } else if (s.find(':') != colonPos) { return Status(ErrorCodes::FailedToParse, str::stream() << "More than one ':' detected. If this is an ipv6 address," << " it needs to be surrounded by '[' and ']'; " << s.toString()); } if (hostPart.empty()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Empty host component parsing HostAndPort from \"" << escape(s.toString()) << "\""); } int port; if (colonPos != std::string::npos) { const StringData portPart = s.substr(colonPos + 1); Status status = parseNumberFromStringWithBase(portPart, 10, &port); if (!status.isOK()) { return status; } if (port <= 0) { return Status(ErrorCodes::FailedToParse, str::stream() << "Port number " << port << " out of range parsing HostAndPort from \"" << escape(s.toString()) << "\""); } } else { port = -1; } _host = hostPart.toString(); _port = port; return Status::OK(); }
int versionCmp(const StringData rhs, const StringData lhs) { if (rhs == lhs) return 0; // handle "1.2.3-" and "1.2.3-pre" if (rhs.size() < lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') return +1; } else if (rhs.size() > lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') return -1; } return LexNumCmp::cmp(rhs, lhs, false); }
void WriteConcernErrorDetail::setErrMessage(StringData errMessage) { _errMessage = errMessage.toString(); _isErrMessageSet = true; }
void BatchedUpdateRequest::setCollName(const StringData& collName) { _collName = collName.toString(); _isCollNameSet = true; }
void RangeDeleterMockEnv::addCursorId(const StringData& ns, CursorId id) { scoped_lock sl(_cursorMapMutex); _cursorMap[ns.toString()].insert(id); }
void RangeDeleterMockEnv::removeCursorId(const StringData& ns, CursorId id) { scoped_lock sl(_cursorMapMutex); _cursorMap[ns.toString()].erase(id); }
NamespaceIndex::NamespaceIndex(const string &dir, const StringData& database) : _dir(dir), _nsdbFilename(database.toString() + ".ns"), _database(database.toString()), _openRWLock("nsOpenRWLock") {}
void CurOp::setNS( const StringData& ns ) { ns.substr( 0, Namespace::MaxNsLen ).copyTo( _ns, true ); }
Status ModifierRename::prepare(mutablebson::Element root, const StringData& matchedField, ExecInfo* execInfo) { // Rename doesn't work with positional fields ($) dassert(matchedField.empty()); _preparedState.reset(new PreparedState(root)); // Locate the to field name in 'root', which must exist. size_t fromIdxFound; Status status = pathsupport::findLongestPrefix(_fromFieldRef, root, &fromIdxFound, &_preparedState->fromElemFound); const bool sourceExists = (_preparedState->fromElemFound.ok() && fromIdxFound == (_fromFieldRef.numParts() - 1)); // If we can't find the full element in the from field then we can't do anything. if (!status.isOK() || !sourceExists) { execInfo->noOp = true; _preparedState->fromElemFound = root.getDocument().end(); // TODO: remove this special case from existing behavior if (status.code() == ErrorCodes::PathNotViable) { return status; } return Status::OK(); } // Ensure no array in ancestry if what we found is not at the root mutablebson::Element curr = _preparedState->fromElemFound.parent(); if (curr != curr.getDocument().root()) while (curr.ok() && (curr != curr.getDocument().root())) { if (curr.getType() == Array) return Status(ErrorCodes::BadValue, str::stream() << "The source field cannot be an array element, '" << _fromFieldRef.dottedField() << "' in doc with " << findElementNamed(root.leftChild(), "_id").toString() << " has an array field called '" << curr.getFieldName() << "'"); curr = curr.parent(); } // "To" side validation below status = pathsupport::findLongestPrefix(_toFieldRef, root, &_preparedState->toIdxFound, &_preparedState->toElemFound); // FindLongestPrefix may return not viable or any other error and then we cannot proceed. if (status.code() == ErrorCodes::NonExistentPath) { // Not an error condition as we will create the "to" path as needed. } else if (!status.isOK()) { return status; } const bool destExists = _preparedState->toElemFound.ok() && (_preparedState->toIdxFound == (_toFieldRef.numParts()-1)); // Ensure no array in ancestry of "to" Element // Set to either parent, or node depending on if the full path element was found curr = (destExists ? _preparedState->toElemFound.parent() : _preparedState->toElemFound); if (curr != curr.getDocument().root()) { while (curr.ok()) { if (curr.getType() == Array) return Status(ErrorCodes::BadValue, str::stream() << "The destination field cannot be an array element, '" << _fromFieldRef.dottedField() << "' in doc with " << findElementNamed(root.leftChild(), "_id").toString() << " has an array field called '" << curr.getFieldName() << "'"); curr = curr.parent(); } } // We register interest in the field name. The driver needs this info to sort out if // there is any conflict among mods. execInfo->fieldRef[0] = &_fromFieldRef; execInfo->fieldRef[1] = &_toFieldRef; execInfo->noOp = false; return Status::OK(); }
Status ModifierPull::prepare(mb::Element root, const StringData& matchedField, ExecInfo* execInfo) { _preparedState.reset(new PreparedState(root.getDocument())); // If we have a $-positional field, it is time to bind it to an actual field part. if (_posDollar) { if (matchedField.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "The positional operator did not find the match " "needed from the query. Unexpanded update: " << _fieldRef.dottedField()); } _fieldRef.setPart(_posDollar, matchedField); } // Locate the field name in 'root'. Status status = pathsupport::findLongestPrefix(_fieldRef, root, &_preparedState->idxFound, &_preparedState->elemFound); // FindLongestPrefix may say the path does not exist at all, which is fine here, or // that the path was not viable or otherwise wrong, in which case, the mod cannot // proceed. if (status.code() == ErrorCodes::NonExistentPath) { _preparedState->elemFound = root.getDocument().end(); } else if (!status.isOK()) { return status; } // We register interest in the field name. The driver needs this info to sort out if // there is any conflict among mods. execInfo->fieldRef[0] = &_fieldRef; if (!_preparedState->elemFound.ok() || _preparedState->idxFound < (_fieldRef.numParts() - 1)) { // If no target element exists, then there is nothing to do here. _preparedState->noOp = execInfo->noOp = true; return Status::OK(); } // This operation only applies to arrays if (_preparedState->elemFound.getType() != mongo::Array) return Status( ErrorCodes::BadValue, "Cannot apply $pull to a non-array value"); // If the array is empty, there is nothing to pull, so this is a noop. if (!_preparedState->elemFound.hasChildren()) { _preparedState->noOp = execInfo->noOp = true; return Status::OK(); } // Walk the values in the array mb::Element cursor = _preparedState->elemFound.leftChild(); while (cursor.ok()) { if (isMatch(cursor)) _preparedState->elementsToRemove.push_back(cursor); cursor = cursor.rightSibling(); } // If we didn't find any elements to add, then this is a no-op, and therefore in place. if (_preparedState->elementsToRemove.empty()) { _preparedState->noOp = execInfo->noOp = true; } return Status::OK(); }
void ClientCursor::invalidate(const StringData& ns) { Lock::assertWriteLocked(ns); size_t dot = ns.find( '.' ); verify( dot != string::npos ); // first (and only) dot is the last char bool isDB = dot == ns.size() - 1; Database *db = cc().database(); verify(db); verify(ns.startsWith(db->name())); recursive_scoped_lock cclock(ccmutex); // Look at all active non-cached Runners. These are the runners that are in auto-yield mode // that are not attached to the the client cursor. For example, all internal runners don't // need to be cached -- there will be no getMore. for (set<Runner*>::iterator it = nonCachedRunners.begin(); it != nonCachedRunners.end(); ++it) { Runner* runner = *it; const string& runnerNS = runner->ns(); if ( ( isDB && StringData(runnerNS).startsWith(ns) ) || ns == runnerNS ) { runner->kill(); } } // Look at all cached ClientCursor(s). The CC may have a Runner, a Cursor, or nothing (see // sharding_block.h). CCById::const_iterator it = clientCursorsById.begin(); while (it != clientCursorsById.end()) { ClientCursor* cc = it->second; // Aggregation cursors don't have their lifetime bound to the underlying collection. if (cc->isAggCursor) { ++it; continue; } // We're only interested in cursors over one db. if (cc->_db != db) { ++it; continue; } // Note that a valid ClientCursor state is "no cursor no runner." This is because // the set of active cursor IDs in ClientCursor is used as representation of query // state. See sharding_block.h. TODO(greg,hk): Move this out. if (NULL == cc->_runner.get()) { ++it; continue; } bool shouldDelete = false; // We will only delete CCs with runners that are not actively in use. The runners that // are actively in use are instead kill()-ed. if (NULL != cc->_runner.get()) { if (isDB || cc->_runner->ns() == ns) { // If there is a pinValue >= 100, somebody is actively using the CC and we do // not delete it. Instead we notify the holder that we killed it. The holder // will then delete the CC. if (cc->_pinValue >= 100) { cc->_runner->kill(); } else { // pinvalue is <100, so there is nobody actively holding the CC. We can // safely delete it as nobody is holding the CC. shouldDelete = true; } } } if (shouldDelete) { ClientCursor* toDelete = it->second; CursorId id = toDelete->cursorid(); delete toDelete; // We're not following the usual paradigm of saving it, ++it, and deleting the saved // 'it' because deleting 'it' might invalidate the next thing in clientCursorsById. // TODO: Why? it = clientCursorsById.upper_bound(id); } else { ++it; } } }
Lock::DBRead::DBRead( const StringData& ns ) : ScopedLock( 'r' ), _what(ns.data()), _nested(false) { lockDB( _what ); }
inline void ArrayBigBlobs::add_string(StringData value) { BinaryData bin(value.data(), value.size()); bool add_zero_term = true; add(bin, add_zero_term); }
inline DataType Variant::convertToNumeric(int64_t *lval, double *dval) const { StringData *s = getStringData(); assert(s); return s->isNumericWithVal(*lval, *dval, 1); }
inline void ArrayBigBlobs::insert_string(std::size_t ndx, StringData value) { BinaryData bin(value.data(), value.size()); bool add_zero_term = true; insert(ndx, bin, add_zero_term); }
int64_t operator()(StringData v) const { return v.size(); }
BSONObj BSONElement::wrap(StringData newName) const { BSONObjBuilder b(size() + 6 + newName.size()); b.appendAs(*this, newName); return b.obj(); }
Status Database::dropCollection( const StringData& fullns ) { LOG(1) << "dropCollection: " << fullns << endl; Collection* collection = getCollection( fullns ); if ( !collection ) { // collection doesn't exist return Status::OK(); } _initForWrites(); { NamespaceString s( fullns ); verify( s.db() == _name ); if( s.isSystem() ) { if( s.coll() == "system.profile" ) { if ( _profile != 0 ) return Status( ErrorCodes::IllegalOperation, "turn off profiling before dropping system.profile collection" ); } else { return Status( ErrorCodes::IllegalOperation, "can't drop system ns" ); } } } BackgroundOperation::assertNoBgOpInProgForNs( fullns ); audit::logDropCollection( currentClient.get(), fullns ); try { Status s = collection->getIndexCatalog()->dropAllIndexes( true ); if ( !s.isOK() ) { warning() << "could not drop collection, trying to drop indexes" << fullns << " because of " << s.toString(); return s; } } catch( DBException& e ) { stringstream ss; ss << "drop: dropIndexes for collection failed - consider trying repair "; ss << " cause: " << e.what(); warning() << ss.str() << endl; return Status( ErrorCodes::InternalError, ss.str() ); } verify( collection->_details->getTotalIndexCount() == 0 ); LOG(1) << "\t dropIndexes done" << endl; ClientCursor::invalidate( fullns ); Top::global.collectionDropped( fullns ); Status s = _dropNS( fullns ); _clearCollectionCache( fullns ); // we want to do this always if ( !s.isOK() ) return s; DEV { // check all index collection entries are gone string nstocheck = fullns.toString() + ".$"; scoped_lock lk( _collectionLock ); for ( CollectionMap::iterator i = _collections.begin(); i != _collections.end(); ++i ) { string temp = i->first; if ( temp.find( nstocheck ) != 0 ) continue; log() << "after drop, bad cache entries for: " << fullns << " have " << temp; verify(0); } } return Status::OK(); }
EntryInsertion(StringData ns, MMAPV1DatabaseCatalogEntry* entry) : _ns(ns.toString()), _entry(entry) {}
APCHandle::Pair APCHandle::Create(const Variant& source, bool serialized, APCHandleLevel level, bool unserializeObj) { auto type = source.getType(); // this gets rid of the ref, if it was one switch (type) { case KindOfUninit: { auto value = APCTypedValue::tvUninit(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfNull: { auto value = APCTypedValue::tvNull(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfBoolean: { auto value = source.getBoolean() ? APCTypedValue::tvTrue() : APCTypedValue::tvFalse(); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfInt64: { auto value = new APCTypedValue(source.getInt64()); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfDouble: { auto value = new APCTypedValue(source.getDouble()); return {value->getHandle(), sizeof(APCTypedValue)}; } case KindOfPersistentString: case KindOfString: { StringData* s = source.getStringData(); if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. return APCString::MakeSerializedObject(apc_reserialize(String{s})); } if (s->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticStr{}, s); return APCHandle::Pair{value->getHandle(), sizeof(APCTypedValue)}; } auto const st = lookupStaticString(s); if (st) { auto value = new APCTypedValue(APCTypedValue::StaticStr{}, st); return {value->getHandle(), sizeof(APCTypedValue)}; } if (level == APCHandleLevel::Outer && apcExtension::UseUncounted) { auto st = StringData::MakeUncounted(s->slice()); auto value = new APCTypedValue(APCTypedValue::UncountedStr{}, st); return {value->getHandle(), st->size() + sizeof(APCTypedValue)}; } return APCString::MakeSharedString(s); } case KindOfPersistentArray: case KindOfArray: { auto ad = source.getArrayData(); if (ad->isStatic()) { auto value = new APCTypedValue(APCTypedValue::StaticArr{}, ad); return {value->getHandle(), sizeof(APCTypedValue)}; } return APCArray::MakeSharedArray(source.getArrayData(), level, unserializeObj); } case KindOfObject: if (source.getObjectData()->isCollection()) { return APCCollection::Make(source.getObjectData(), level, unserializeObj); } return unserializeObj ? APCObject::Construct(source.getObjectData()) : APCString::MakeSerializedObject(apc_serialize(source)); case KindOfResource: // TODO Task #2661075: Here and elsewhere in the runtime, we convert // Resources to the empty array during various serialization operations, // which does not match Zend behavior. We should fix this. return APCArray::MakeSharedEmptyArray(); case KindOfRef: case KindOfClass: return {nullptr, 0}; } not_reached(); }
// Rollback removing the collection from the cache. Takes ownership of the cachedEntry, // and will delete it if removal is final. EntryRemoval(StringData ns, MMAPV1DatabaseCatalogEntry* catalogEntry, Entry* cachedEntry) : _ns(ns.toString()), _catalogEntry(catalogEntry), _cachedEntry(cachedEntry) {}
int LexNumCmp::cmp( const StringData& sd1, const StringData& sd2, bool lexOnly ) { bool startWord = true; size_t s1 = 0; size_t s2 = 0; while( s1 < sd1.size() && s2 < sd2.size() ) { bool d1 = ( sd1[s1] == '.' ); bool d2 = ( sd2[s2] == '.' ); if ( d1 && !d2 ) return -1; if ( d2 && !d1 ) return 1; if ( d1 && d2 ) { ++s1; ++s2; startWord = true; continue; } bool p1 = ( sd1[s1] == (char)255 ); bool p2 = ( sd2[s2] == (char)255 ); if ( p1 && !p2 ) return 1; if ( p2 && !p1 ) return -1; if ( !lexOnly ) { bool n1 = isdigit( sd1[s1] ); bool n2 = isdigit( sd2[s2] ); if ( n1 && n2 ) { // get rid of leading 0s if ( startWord ) { while ( s1 < sd1.size() && sd1[s1] == '0' ) s1++; while ( s2 < sd2.size() && sd2[s2] == '0' ) s2++; } size_t e1 = s1; size_t e2 = s2; while ( e1 < sd1.size() && isdigit( sd1[e1] ) ) e1++; while ( e2 < sd2.size() && isdigit( sd2[e2] ) ) e2++; size_t len1 = e1-s1; size_t len2 = e2-s2; int result; // if one is longer than the other, return if ( len1 > len2 ) { return 1; } else if ( len2 > len1 ) { return -1; } // if the lengths are equal, just strcmp else { result = strncmp( sd1.rawData() + s1, sd2.rawData() + s2, len1 ); if ( result ) return ( result > 0) ? 1 : -1; } // otherwise, the numbers are equal s1 = e1; s2 = e2; startWord = false; continue; } if ( n1 ) return 1; if ( n2 ) return -1; } if ( sd1[s1] > sd2[s2] ) return 1; if ( sd2[s2] > sd1[s1] ) return -1; s1++; s2++; startWord = false; } if ( s1 < sd1.size() && sd1[s1] ) return 1; if ( s2 < sd2.size() && sd2[s2] ) return -1; return 0; }
Status MMAPV1DatabaseCatalogEntry::_renameSingleNamespace(OperationContext* txn, StringData fromNS, StringData toNS, bool stayTemp) { // some sanity checking NamespaceDetails* fromDetails = _namespaceIndex.details(fromNS); if (!fromDetails) return Status(ErrorCodes::BadValue, "from namespace doesn't exist"); if (_namespaceIndex.details(toNS)) return Status(ErrorCodes::BadValue, "to namespace already exists"); // at this point, we haven't done anything destructive yet // ---- // actually start moving // ---- // this could throw, but if it does we're ok _namespaceIndex.add_ns(txn, toNS, fromDetails); NamespaceDetails* toDetails = _namespaceIndex.details(toNS); try { toDetails->copyingFrom(txn, toNS, _namespaceIndex, fromDetails); // fixes extraOffset } catch (DBException&) { // could end up here if .ns is full - if so try to clean up / roll back a little _namespaceIndex.kill_ns(txn, toNS); throw; } // at this point, code .ns stuff moved _namespaceIndex.kill_ns(txn, fromNS); fromDetails = NULL; // fix system.namespaces BSONObj newSpec; RecordId oldSpecLocation = getCollectionCatalogEntry(fromNS)->getNamespacesRecordId(); invariant(!oldSpecLocation.isNull()); { BSONObj oldSpec = _getNamespaceRecordStore()->dataFor(txn, oldSpecLocation).releaseToBson(); invariant(!oldSpec.isEmpty()); BSONObjBuilder b; BSONObjIterator i(oldSpec.getObjectField("options")); while (i.more()) { BSONElement e = i.next(); if (strcmp(e.fieldName(), "create") != 0) { if (stayTemp || (strcmp(e.fieldName(), "temp") != 0)) b.append(e); } else { b << "create" << toNS; } } newSpec = b.obj(); } RecordId rid = _addNamespaceToNamespaceCollection(txn, toNS, newSpec.isEmpty() ? 0 : &newSpec); _getNamespaceRecordStore()->deleteRecord(txn, oldSpecLocation); Entry*& entry = _collections[toNS.toString()]; invariant(entry == NULL); txn->recoveryUnit()->registerChange(new EntryInsertion(toNS, this)); entry = new Entry(); _removeFromCache(txn->recoveryUnit(), fromNS); _insertInCache(txn, toNS, rid, entry); return Status::OK(); }
bool hasFunctionIdentifier(StringData code) { if (code.size() < 9 || code.find("function") != 0) return false; return code[8] == ' ' || code[8] == '('; }
Lock::DBWrite::DBWrite( const StringData& ns ) : ScopedLock( 'w' ), _what(ns.data()), _nested(false) { lockDB( _what ); }
static ValueType from_string(ContextType ctx, StringData string) { return Value::from_string(ctx, string.data()); }
Status ModifierAddToSet::prepare(mb::Element root, StringData matchedField, ExecInfo* execInfo) { _preparedState.reset(new PreparedState(root.getDocument())); // If we have a $-positional field, it is time to bind it to an actual field part. if (_posDollar) { if (matchedField.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "The positional operator did not find the match " "needed from the query. Unexpanded update: " << _fieldRef.dottedField()); } _fieldRef.setPart(_posDollar, matchedField); } // Locate the field name in 'root'. Status status = pathsupport::findLongestPrefix( _fieldRef, root, &_preparedState->idxFound, &_preparedState->elemFound); // FindLongestPrefix may say the path does not exist at all, which is fine here, or // that the path was not viable or otherwise wrong, in which case, the mod cannot // proceed. if (status.code() == ErrorCodes::NonExistentPath) { _preparedState->elemFound = root.getDocument().end(); } else if (!status.isOK()) { return status; } // We register interest in the field name. The driver needs this info to sort out if // there is any conflict among mods. execInfo->fieldRef[0] = &_fieldRef; // // in-place and no-op logic // // If the field path is not fully present, then this mod cannot be in place, nor is a // noOp. if (!_preparedState->elemFound.ok() || _preparedState->idxFound < (_fieldRef.numParts() - 1)) { // If no target element exists, we will simply be creating a new array. _preparedState->addAll = true; return Status::OK(); } // This operation only applies to arrays if (_preparedState->elemFound.getType() != mongol::Array) { mb::Element idElem = mb::findElementNamed(root.leftChild(), "_id"); return Status(ErrorCodes::BadValue, str::stream() << "Cannot apply $addToSet to a non-array field. Field named '" << _preparedState->elemFound.getFieldName() << "' has a non-array type " << typeName(_preparedState->elemFound.getType()) << " in the document " << idElem.toString()); } // If the array is empty, then we don't need to check anything: all of the values are // going to be added. if (!_preparedState->elemFound.hasChildren()) { _preparedState->addAll = true; return Status::OK(); } // For each value in the $each clause, compare it against the values in the array. If // the element is not present, record it as one to add. mb::Element eachIter = _val.leftChild(); while (eachIter.ok()) { mb::Element where = mb::findElement(_preparedState->elemFound.leftChild(), mb::woEqualTo(eachIter, false)); if (!where.ok()) { // The element was not found. Record the element from $each as one to be added. _preparedState->elementsToAdd.push_back(eachIter); } eachIter = eachIter.rightSibling(); } // If we didn't find any elements to add, then this is a no-op. if (_preparedState->elementsToAdd.empty()) { _preparedState->noOp = execInfo->noOp = true; } return Status::OK(); }