StatusWith<bool> SaslSCRAMSHA1ServerConversation::step(const StringData& inputData,
                                                           std::string* outputData) {

        std::vector<std::string> input = StringSplitter::split(inputData.toString(), ",");
        _step++;

        if (_step > 3 || _step <= 0) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                mongoutils::str::stream() << "Invalid SCRAM-SHA-1 authentication step: " << _step);
        }
        if (_step == 1) {
            return _firstStep(input, outputData);
        }
        if (_step == 2) {
            return _secondStep(input, outputData);
        }

        *outputData = "";

        return StatusWith<bool>(true);
    }
Example #2
0
Status MobileKVEngine::createRecordStore(OperationContext* opCtx,
                                         StringData ns,
                                         StringData ident,
                                         const CollectionOptions& options) {
    // TODO: eventually will support file renaming but otherwise do not use collection options.

    // Mobile SE doesn't support creating an oplog
    if (NamespaceString::oplog(ns)) {
        return Status(ErrorCodes::InvalidOptions,
                      "Replication is not supported by the mobile storage engine");
    }

    // Mobile doesn't support capped collections
    if (options.capped) {
        return Status(ErrorCodes::InvalidOptions,
                      "Capped collections are not supported by the mobile storage engine");
    }

    MobileRecordStore::create(opCtx, ident.toString());
    return Status::OK();
}
void WiredTigerKVEngine::_checkIdentPath(StringData ident) {
    size_t start = 0;
    size_t idx;
    while ((idx = ident.find('/', start)) != string::npos) {
        StringData dir = ident.substr(0, idx);

        boost::filesystem::path subdir = _path;
        subdir /= dir.toString();
        if (!boost::filesystem::exists(subdir)) {
            LOG(1) << "creating subdirectory: " << dir;
            try {
                boost::filesystem::create_directory(subdir);
            } catch (const std::exception& e) {
                error() << "error creating path " << subdir.string() << ' ' << e.what();
                throw;
            }
        }

        start = idx + 1;
    }
}
Example #4
0
    //
    // delete all collections, their metadata, then the database
    //
    Status BLTreeEngine::dropDatabase(
        OperationContext* ctx,
        const StringData& db )
    {
        const string prefix = db.toString() + ".";
        boost::mutex::scoped_lock lk( _entryMapMutex );
        vector<string> toDrop;

        for (EntryMap::const_iterator i = _entryMap.begin(); i != _entryMap.end(); ++i ) {
            const StringData& ns = i->first;
            if ( ns.startsWith( prefix ) ) {
                toDrop.push_back( ns.toString() );
            }
        }

        for (vector<string>::const_iterator j = toDrop.begin(); j != toDrop.end(); ++j ) {
            _dropCollection_inlock( ctx, *j );
        }

        return closeDatabase( ctx, db );
    }
Status CommittedOpTimeMetadataHook::readReplyMetadata(OperationContext* opCtx,
                                                      StringData replySource,
                                                      const BSONObj& metadataObj) {
    auto lastCommittedOpTimeField = metadataObj[kLastCommittedOpTimeFieldName];
    if (lastCommittedOpTimeField.eoo()) {
        return Status::OK();
    }

    invariant(lastCommittedOpTimeField.type() == BSONType::bsonTimestamp);

    // replySource is the HostAndPort of a single server, except when this hook is triggered
    // through DBClientReplicaSet, when it will be a replica set connection string. The
    // shardRegistry stores connection strings and hosts in its lookup table, in addition to shard
    // ids, so replySource can be correctly passed on to ShardRegistry::getShardNoReload.
    auto shard = Grid::get(_service)->shardRegistry()->getShardNoReload(replySource.toString());
    if (shard) {
        shard->updateLastCommittedOpTime(LogicalTime(lastCommittedOpTimeField.timestamp()));
    }

    return Status::OK();
}
void NamespaceIndex::kill_ns(OperationContext* txn, StringData ns) {
    const NamespaceString nss(ns.toString());
    invariant(txn->lockState()->isDbLockedForMode(nss.db(), MODE_X));

    const Namespace n(ns);
    _ht->kill(txn, n);

    if (ns.size() <= Namespace::MaxNsColletionLen) {
        // Larger namespace names don't have room for $extras so they can't exist. The code
        // below would cause an "$extra: ns too large" error and stacktrace to be printed to the
        // log even though everything is fine.
        for (int i = 0; i <= 1; i++) {
            try {
                Namespace extra(n.extraName(i));
                _ht->kill(txn, extra);
            } catch (DBException&) {
                LOG(3) << "caught exception in kill_ns" << endl;
            }
        }
    }
}
Example #7
0
    Status ModifierCurrentDate::prepare(mutablebson::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 (_pathReplacementPosition) {
            if (matchedField.empty()) {
                return Status(ErrorCodes::BadValue, "matched field not provided");
            }
            _preparedState->pathReplacementString = matchedField.toString();
            _updatePath.setPart(_pathReplacementPosition, _preparedState->pathReplacementString);
        }

        // Locate the field name in 'root'. Note that we may not have all the parts in the path
        // in the doc -- which is fine. Our goal now is merely to reason about whether this mod
        // apply is a noOp or whether is can be in place. The remaining path, if missing, will
        // be created during the apply.
        Status status = pathsupport::findLongestPrefix(_updatePath,
                                                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] = &_updatePath;

        return Status::OK();
    }
Example #8
0
Database::Database(OperationContext* txn, StringData name, DatabaseCatalogEntry* dbEntry)
    : _name(name.toString()),
      _dbEntry(dbEntry),
      _profileName(_name + ".system.profile"),
      _indexesName(_name + ".system.indexes"),
      _viewsName(_name + ".system.views"),
      _views(txn, this) {
    Status status = validateDBName(_name);
    if (!status.isOK()) {
        warning() << "tried to open invalid db: " << _name << endl;
        uasserted(10028, status.toString());
    }

    _profile = serverGlobalParams.defaultProfile;

    list<string> collections;
    _dbEntry->getCollectionNamespaces(&collections);
    for (list<string>::const_iterator it = collections.begin(); it != collections.end(); ++it) {
        const string ns = *it;
        _collections[ns] = _getOrCreateCollectionInstance(txn, ns);
    }
}
    bool AuthzManagerExternalStateMongos::tryAcquireAuthzUpdateLock(const StringData& why) {
        boost::lock_guard<boost::mutex> lkLocal(_distLockGuard);
        if (_authzDataUpdateLock.get()) {
            return false;
        }

        // Temporarily put into an auto_ptr just in case there is an exception thrown during
        // lock acquisition.
        std::auto_ptr<ScopedDistributedLock> lockHolder(new ScopedDistributedLock(
                configServer.getConnectionString(), "authorizationData"));
        lockHolder->setLockMessage(why.toString());

        std::string errmsg;
        if (!lockHolder->acquire(_authzUpdateLockAcquisitionTimeoutMillis, &errmsg)) {
            warning() <<
                    "Error while attempting to acquire distributed lock for user modification: " <<
                    errmsg << endl;
            return false;
        }
        _authzDataUpdateLock.reset(lockHolder.release());
        return true;
    }
Example #10
0
rpc::UniqueReply MockRemoteDBServer::runCommandWithMetadata(MockRemoteDBServer::InstanceID id,
                                                            StringData database,
                                                            StringData commandName,
                                                            const BSONObj& metadata,
                                                            const BSONObj& commandArgs) {
    checkIfUp(id);
    std::string cmdName = commandName.toString();

    BSONObj reply;
    {
        scoped_spinlock lk(_lock);

        uassert(ErrorCodes::IllegalOperation,
                str::stream() << "no reply for command: " << commandName,
                _cmdMap.count(cmdName));

        reply = _cmdMap[cmdName]->next();
    }

    if (_delayMilliSec > 0) {
        mongo::sleepmillis(_delayMilliSec);
    }

    checkIfUp(id);

    {
        scoped_spinlock lk(_lock);
        _cmdCount++;
    }

    // We need to construct a reply message - it will always be read through a view so it
    // doesn't matter whether we use CommandReplBuilder or LegacyReplyBuilder
    auto message = rpc::CommandReplyBuilder{}
                       .setMetadata(rpc::makeEmptyMetadata())
                       .setCommandReply(reply)
                       .done();
    auto replyView = stdx::make_unique<rpc::CommandReply>(message.get());
    return rpc::UniqueReply(std::move(message), std::move(replyView));
}
Example #11
0
        static Status checkUniqueIndexConstraints(OperationContext* txn,
                                                  const StringData& ns,
                                                  const BSONObj& newIdxKey) {
            txn->lockState()->assertWriteLocked( ns );

            if ( shardingState.enabled() ) {
                CollectionMetadataPtr metadata(
                        shardingState.getCollectionMetadata( ns.toString() ));

                if ( metadata ) {
                    ShardKeyPattern shardKeyPattern(metadata->getKeyPattern());
                    if (!shardKeyPattern.isUniqueIndexCompatible(newIdxKey)) {
                        return Status(ErrorCodes::CannotCreateIndex,
                            str::stream() << "cannot create unique index over " << newIdxKey
                                          << " with shard key pattern "
                                          << shardKeyPattern.toBSON());
                    }
                }
            }

            return Status::OK();
        }
Example #12
0
StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx, StringData uri) {
    invariant(opCtx);
    WiredTigerCursor curwrap("metadata:create", WiredTigerSession::kMetadataTableId, false, opCtx);
    WT_CURSOR* cursor = curwrap.get();
    invariant(cursor);
    std::string strUri = uri.toString();
    cursor->set_key(cursor, strUri.c_str());
    int ret = cursor->search(cursor);
    if (ret == WT_NOTFOUND) {
        return StatusWith<std::string>(ErrorCodes::NoSuchKey,
                                       str::stream() << "Unable to find metadata for " << uri);
    } else if (ret != 0) {
        return StatusWith<std::string>(wtRCToStatus(ret));
    }
    const char* metadata = NULL;
    ret = cursor->get_value(cursor, &metadata);
    if (ret != 0) {
        return StatusWith<std::string>(wtRCToStatus(ret));
    }
    invariant(metadata);
    return StatusWith<std::string>(metadata);
}
Example #13
0
    // non public api
    Status RocksEngine::_createIdentPrefix(StringData ident) {
        uint32_t prefix = 0;
        {
            boost::mutex::scoped_lock lk(_identPrefixMapMutex);
            if (_identPrefixMap.find(ident) != _identPrefixMap.end()) {
                // already exists
                return Status::OK();
            }

            prefix = ++_maxPrefix;
            _identPrefixMap[ident] = prefix;
        }

        BSONObjBuilder builder;
        builder.append("prefix", static_cast<int32_t>(prefix));
        BSONObj config = builder.obj();

        auto s = _db->Put(rocksdb::WriteOptions(), kMetadataPrefix + ident.toString(),
                          rocksdb::Slice(config.objdata(), config.objsize()));

        return toMongoStatus(s);
    }
Example #14
0
Status KVCatalog::dropCollection(OperationContext* opCtx, StringData ns) {
    invariant(opCtx->lockState() == NULL ||
              opCtx->lockState()->isDbLockedForMode(nsToDatabaseSubstring(ns), MODE_X));
    std::unique_ptr<Lock::ResourceLock> rLk;
    if (!_isRsThreadSafe && opCtx->lockState()) {
        rLk.reset(new Lock::ResourceLock(opCtx->lockState(), resourceIdCatalogMetadata, MODE_X));
    }

    stdx::lock_guard<stdx::mutex> lk(_identsLock);
    const NSToIdentMap::iterator it = _idents.find(ns.toString());
    if (it == _idents.end()) {
        return Status(ErrorCodes::NamespaceNotFound, "collection not found");
    }

    opCtx->recoveryUnit()->registerChange(new RemoveIdentChange(this, ns, it->second));

    LOG(1) << "deleting metadata for " << ns << " @ " << it->second.storedLoc;
    _rs->deleteRecord(opCtx, it->second.storedLoc);
    _idents.erase(it);

    return Status::OK();
}
Example #15
0
std::unique_ptr<mongo::RecordStore> KVEngine::getRecordStore(OperationContext* opCtx,
                                                             StringData ns,
                                                             StringData ident,
                                                             const CollectionOptions& options) {
    std::unique_ptr<mongo::RecordStore> recordStore;
    if (options.capped) {
        if (NamespaceString::oplog(ns))
            _visibilityManager = std::make_unique<VisibilityManager>();
        recordStore = std::make_unique<RecordStore>(
            ns,
            ident,
            options.capped,
            options.cappedSize ? options.cappedSize : kDefaultCappedSizeBytes,
            options.cappedMaxDocs ? options.cappedMaxDocs : -1,
            /*cappedCallback*/ nullptr,
            _visibilityManager.get());
    } else {
        recordStore = std::make_unique<RecordStore>(ns, ident, options.capped);
    }
    _idents[ident.toString()] = true;
    return recordStore;
}
    bool RangeDeleterMockEnv::deleteRange(OperationContext* txn,
                                          const StringData& ns,
                                          const BSONObj& min,
                                          const BSONObj& max,
                                          const BSONObj& shardKeyPattern,
                                          bool secondaryThrottle,
                                          string* errMsg) {

        {
            scoped_lock sl(_pauseDeleteMutex);
            bool wasInitiallyPaused = _pauseDelete;

            if (_pauseDelete) {
                _pausedCount++;
                _pausedDeleteChangeCV.notify_one();
            }

            while (_pauseDelete) {
                _pausedCV.wait(sl.boost());
            }

            _pauseDelete = wasInitiallyPaused;
        }

        {
            scoped_lock sl(_deleteListMutex);

            DeletedRange entry;
            entry.ns = ns.toString();
            entry.min = min.getOwned();
            entry.max = max.getOwned();
            entry.shardKeyPattern = shardKeyPattern.getOwned();

            _deleteList.push_back(entry);
        }

        return true;
    }
Example #17
0
StatusWith<std::string> WiredTigerUtil::getMetadataRaw(WT_SESSION* session, StringData uri) {
    WT_CURSOR* cursor;
    invariantWTOK(session->open_cursor(session, "metadata:create", nullptr, "", &cursor));
    invariant(cursor);
    ON_BLOCK_EXIT([cursor] { invariantWTOK(cursor->close(cursor)); });

    std::string strUri = uri.toString();
    cursor->set_key(cursor, strUri.c_str());
    int ret = cursor->search(cursor);
    if (ret == WT_NOTFOUND) {
        return StatusWith<std::string>(ErrorCodes::NoSuchKey,
                                       str::stream() << "Unable to find metadata for " << uri);
    } else if (ret != 0) {
        return StatusWith<std::string>(wtRCToStatus(ret));
    }
    const char* metadata = NULL;
    ret = cursor->get_value(cursor, &metadata);
    if (ret != 0) {
        return StatusWith<std::string>(wtRCToStatus(ret));
    }
    invariant(metadata);
    return StatusWith<std::string>(metadata);
}
Example #18
0
BSONObj KVCatalog::_findEntry(OperationContext* opCtx, StringData ns, RecordId* out) const {
    RecordId dl;
    {
        stdx::lock_guard<stdx::mutex> lk(_identsLock);
        NSToIdentMap::const_iterator it = _idents.find(ns.toString());
        invariant(it != _idents.end());
        dl = it->second.storedLoc;
    }

    LOG(3) << "looking up metadata for: " << ns << " @ " << dl;
    RecordData data;
    if (!_rs->findRecord(opCtx, dl, &data)) {
        // since the in memory meta data isn't managed with mvcc
        // its possible for different transactions to see slightly
        // different things, which is ok via the locking above.
        return BSONObj();
    }

    if (out)
        *out = dl;

    return data.releaseToBson().getOwned();
}
Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj,
                                               StringData cmdName,
                                               const std::string& dbname,
                                               std::string* parsedName,
                                               vector<RoleName>* parsedRoleNames) {
    unordered_set<std::string> validFieldNames;
    validFieldNames.insert(cmdName.toString());
    validFieldNames.insert("roles");

    Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames);
    if (!status.isOK()) {
        return status;
    }

    status = bsonExtractStringField(cmdObj, cmdName, parsedName);
    if (!status.isOK()) {
        return status;
    }

    BSONElement rolesElement;
    status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement);
    if (!status.isOK()) {
        return status;
    }

    status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, parsedRoleNames);
    if (!status.isOK()) {
        return status;
    }

    if (!parsedRoleNames->size()) {
        return Status(ErrorCodes::BadValue,
                      mongoutils::str::stream() << cmdName << " command requires a non-empty "
                                                              "\"roles\" array");
    }
    return Status::OK();
}
Example #20
0
std::unique_ptr<PlanExecutor> InternalPlanner::collectionScan(OperationContext* txn,
                                                              StringData ns,
                                                              Collection* collection,
                                                              PlanExecutor::YieldPolicy yieldPolicy,
                                                              const Direction direction,
                                                              const RecordId startLoc) {
    std::unique_ptr<WorkingSet> ws = stdx::make_unique<WorkingSet>();

    if (NULL == collection) {
        auto eof = stdx::make_unique<EOFStage>(txn);
        // Takes ownership of 'ws' and 'eof'.
        auto statusWithPlanExecutor =
            PlanExecutor::make(txn, std::move(ws), std::move(eof), ns.toString(), yieldPolicy);
        invariant(statusWithPlanExecutor.isOK());
        return std::move(statusWithPlanExecutor.getValue());
    }

    invariant(ns == collection->ns().ns());

    CollectionScanParams params;
    params.collection = collection;
    params.start = startLoc;

    if (FORWARD == direction) {
        params.direction = CollectionScanParams::FORWARD;
    } else {
        params.direction = CollectionScanParams::BACKWARD;
    }

    std::unique_ptr<CollectionScan> cs =
        stdx::make_unique<CollectionScan>(txn, params, ws.get(), nullptr);
    // Takes ownership of 'ws' and 'cs'.
    auto statusWithPlanExecutor =
        PlanExecutor::make(txn, std::move(ws), std::move(cs), collection, yieldPolicy);
    invariant(statusWithPlanExecutor.isOK());
    return std::move(statusWithPlanExecutor.getValue());
}
Example #21
0
        // TODO: This is inefficient.  We could create the tagged tree as part of the PredicateMap
        // construction.
        void tag(MatchExpression* node) {
            StringData path = node->path();

            if (!path.empty()) {

                for (PredicateMap::const_iterator it = _pm.find(path.toString()); _pm.end() != it;
                     ++it) {

                    if (it->second.type == node->matchType()) {
                        EnumeratorTag* td = new EnumeratorTag(&it->second);
                        node->setTag(td);
                        _taggedLeaves.push_back(node);
                        break;
                    }
                }
            }

            // XXX XXX XXX XXX
            // XXX Do we do this if the node is logical, or if it's array, or both?
            // XXX XXX XXX XXX
            for (size_t i = 0; i < node->numChildren(); ++i) {
                tag(const_cast<MatchExpression*>(node->getChild(i)));
            }
        }
void ConfigServerCatalogCacheLoader::getDatabase(
    StringData dbName,
    stdx::function<void(OperationContext*, StatusWith<DatabaseType>)> callbackFn) {
    _threadPool.schedule([ name = dbName.toString(), callbackFn ](auto status) noexcept {
        invariant(status);

        auto opCtx = Client::getCurrent()->makeOperationContext();

        auto swDbt = [&]() -> StatusWith<DatabaseType> {
            try {
                return uassertStatusOK(
                           Grid::get(opCtx.get())
                               ->catalogClient()
                               ->getDatabase(
                                   opCtx.get(), name, repl::ReadConcernLevel::kMajorityReadConcern))
                    .value;
            } catch (const DBException& ex) {
                return ex.toStatus();
            }
        }();

        callbackFn(opCtx.get(), std::move(swDbt));
    });
}
Example #23
0
/**
 * Set a collection option flag for 'UsePowerOf2Sizes' or 'NoPadding'. Appends both the new and
 * old flag setting to the given 'result' builder.
 */
void setCollectionOptionFlag(OperationContext* opCtx,
                             Collection* coll,
                             BSONElement& collOptionElement,
                             BSONObjBuilder* result) {
    const StringData flagName = collOptionElement.fieldNameStringData();

    int flag;

    if (flagName == "usePowerOf2Sizes") {
        flag = CollectionOptions::Flag_UsePowerOf2Sizes;
    } else if (flagName == "noPadding") {
        flag = CollectionOptions::Flag_NoPadding;
    } else {
        flag = 0;
    }

    CollectionCatalogEntry* cce = coll->getCatalogEntry();

    const int oldFlags = cce->getCollectionOptions(opCtx).flags;
    const bool oldSetting = oldFlags & flag;
    const bool newSetting = collOptionElement.trueValue();

    result->appendBool(flagName.toString() + "_old", oldSetting);
    result->appendBool(flagName.toString() + "_new", newSetting);

    const int newFlags = newSetting ? (oldFlags | flag)    // set flag
                                    : (oldFlags & ~flag);  // clear flag

    // NOTE we do this unconditionally to ensure that we note that the user has
    // explicitly set flags, even if they are just setting the default.
    cce->updateFlags(opCtx, newFlags);

    const CollectionOptions newOptions = cce->getCollectionOptions(opCtx);
    invariant(newOptions.flags == newFlags);
    invariant(newOptions.flagsSet);
}
Example #24
0
 AddCollectionChange(Database* db, StringData ns)
     : _db(db)
     , _ns(ns.toString())
 {}
Example #25
0
    Status Database::dropCollection( OperationContext* txn, StringData fullns ) {
        invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X));

        LOG(1) << "dropCollection: " << fullns << endl;
        massertNamespaceNotIndex( fullns, "dropCollection" );

        Collection* collection = getCollection( fullns );
        if ( !collection ) {
            // collection doesn't exist
            return Status::OK();
        }

        {
            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 );

        Status s = collection->getIndexCatalog()->dropAllIndexes(txn, true);
        if ( !s.isOK() ) {
            warning() << "could not drop collection, trying to drop indexes"
                      << fullns << " because of " << s.toString();
            return s;
        }

        verify( collection->_details->getTotalIndexCount( txn ) == 0 );
        LOG(1) << "\t dropIndexes done" << endl;

        Top::global.collectionDropped( fullns );

        s = _dbEntry->dropCollection( txn, fullns );

        _clearCollectionCache( txn, fullns ); // we want to do this always

        if ( !s.isOK() )
            return s;

        DEV {
            // check all index collection entries are gone
            string nstocheck = fullns.toString() + ".$";
            for ( CollectionMap::const_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();
    }
Example #26
0
    bool processObj(const BSONObj &obj) {
        if (obj.hasField("$err")) {
            log() << "error getting oplog: " << obj << endl;
            return false;
        }

        static const char *names[] = {"ts", "op", "ns", "o", "b"};
        BSONElement fields[5];
        obj.getFields(5, names, fields);

        BSONElement &tsElt = fields[0];
        if (!tsElt.ok()) {
            log() << "oplog format error: " << obj << " missing 'ts' field." << endl;
            return false;
        }
        if (tsElt.type() != Date && tsElt.type() != Timestamp) {
            log() << "oplog format error: " << obj << " wrong 'ts' field type." << endl;
            return false;
        }
        _thisTime = OpTime(tsElt.date());

        BSONElement &opElt = fields[1];
        if (!opElt.ok()) {
            log() << "oplog format error: " << obj << " missing 'op' field." << endl;
            return false;
        }
        StringData op = opElt.Stringdata();

        // nop
        if (op == "n") {
            return true;
        }
        // "presence of a database"
        if (op == "db") {
            return true;
        }
        if (op != "c" && op != "i" && op != "u" && op != "d") {
            log() << "oplog format error: " << obj << " has an invalid 'op' field of '" << op << "'." << endl;
            return false;
        }

        if (op != "i" && !_insertBuf.empty()) {
            flushInserts();
        }

        BSONElement &nsElt = fields[2];
        if (!nsElt.ok()) {
            log() << "oplog format error: " << obj << " missing 'ns' field." << endl;
            return false;
        }
        StringData ns = nsElt.Stringdata();
        size_t i = ns.find('.');
        if (i == string::npos) {
            log() << "oplog format error: invalid namespace '" << ns << "' in op " << obj << "." << endl;
            return false;
        }
        StringData dbname = ns.substr(0, i);
        StringData collname = ns.substr(i + 1);

        BSONElement &oElt = fields[3];
        if (!oElt.ok()) {
            log() << "oplog format error: " << obj << " missing 'o' field." << endl;
            return false;
        }
        BSONObj o = obj["o"].Obj();

        if (op == "c") {
            if (collname != "$cmd") {
                log() << "oplog format error: invalid namespace '" << ns << "' for command in op " << obj << "." << endl;
                return false;
            }
            BSONObj info;
            bool ok = _conn.runCommand(dbname.toString(), o, info);
            if (!ok) {
                StringData fieldName = o.firstElementFieldName();
                BSONElement errmsgElt = info["errmsg"];
                StringData errmsg = errmsgElt.type() == String ? errmsgElt.Stringdata() : "";
                bool isDropIndexes = (fieldName == "dropIndexes" || fieldName == "deleteIndexes");
                if (((fieldName == "drop" || isDropIndexes) && errmsg == "ns not found") ||
                    (isDropIndexes && (errmsg == "index not found" || errmsg.find("can't find index with key:") == 0))) {
                    // This is actually ok.  We don't mind dropping something that's not there.
                    LOG(1) << "Tried to replay " << o << ", got " << info << ", ignoring." << endl;
                }
                else {
                    log() << "replay of command " << o << " failed: " << info << endl;
                    return false;
                }
            }
        }
        else {
            string nsstr = ns.toString();
            if (op == "i") {
                if (collname == "system.indexes") {
                    // Can't ensure multiple indexes in the same batch.
                    flushInserts();

                    // For now, we need to strip out any background fields from
                    // ensureIndex.  Once we do hot indexing we can do something more
                    // like what vanilla applyOperation_inlock does.
                    if (o["background"].trueValue()) {
                        BSONObjBuilder builder;
                        BSONObjIterator it(o);
                        while (it.more()) {
                            BSONElement e = it.next();
                            if (strncmp(e.fieldName(), "background", sizeof("background")) != 0) {
                                builder.append(e);
                            }
                        }
                        o = builder.obj();
                    }
                    // We need to warn very carefully about dropDups.
                    if (o["dropDups"].trueValue()) {
                        BSONObjBuilder builder;
                        BSONObjIterator it(o);
                        while (it.more()) {
                            BSONElement e = it.next();
                            if (strncmp(e.fieldName(), "dropDups", sizeof("dropDups")) != 0) {
                                builder.append(e);
                            }
                        }
                        warning() << "Detected an ensureIndex with dropDups: true in " << o << "." << endl;
                        warning() << "This option is not supported in TokuMX, because it deletes arbitrary data." << endl;
                        warning() << "If it were replayed, it could result in a completely different data set than the source database." << endl;
                        warning() << "We will attempt to replay it without dropDups, but if that fails, you must restart your migration process." << endl;
                        _conn.insert(nsstr, o);
                        string err = _conn.getLastError(dbname.toString(), false, false);
                        if (!err.empty()) {
                            log() << "replay of operation " << obj << " failed: " << err << endl;
                            warning() << "You cannot continue processing this replication stream.  You need to restart the migration process." << endl;
                            _running = false;
                            _logAtExit = false;
                            return true;
                        }
                    }
                }
                pushInsert(nsstr, o);
                // Don't call GLE or update _maxOpTimeSynced yet.
                _thisTime = OpTime();
                return true;
            }
            else if (op == "u") {
                BSONElement o2Elt = obj["o2"];
                if (!o2Elt.ok()) {
                    log() << "oplog format error: " << obj << " missing 'o2' field." << endl;
                    return false;
                }
                BSONElement &bElt = fields[4];
                bool upsert = bElt.booleanSafe();
                BSONObj o2 = o2Elt.Obj();
                _conn.update(nsstr, o2, o, upsert, false);
            }
            else if (op == "d") {
                BSONElement &bElt = fields[4];
                bool justOne = bElt.booleanSafe();
                _conn.remove(nsstr, o, justOne);
            }
            string err = _conn.getLastError(dbname.toString(), false, false);
            if (!err.empty()) {
                log() << "replay of operation " << obj << " failed: " << err << endl;
                return false;
            }
        }

        // If we got here, we completed the operation successfully.
        _maxOpTimeSynced = _thisTime;
        _thisTime = OpTime();
        return true;
    }
Example #27
0
void CurOp::setNS_inlock(StringData ns) {
    _ns = ns.toString();
}
Example #28
0
 void CurOp::setNS( const StringData& ns ) {
     // _ns copies the data in the null-terminated ptr it's given
     _ns = ns.toString().c_str();
 }
    Status ModifierAddToSet::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, "matched field not provided");
            }
            _preparedState->boundDollar = matchedField.toString();
            _fieldRef.setPart(_posDollar, _preparedState->boundDollar);
        }

        // 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 < static_cast<int32_t>(_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() != mongo::Array)
            return Status(
                ErrorCodes::BadValue,
                "Cannot apply $addToSet to a non-array value");

        // 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, and therefore in place.
        if (_preparedState->elementsToAdd.empty()) {
            _preparedState->noOp = execInfo->noOp = true;
            execInfo->inPlace = true;
        }

        return Status::OK();
    }
        Status _parseAndValidateInput(BSONObj cmdObj, CreateUserArgs* parsedArgs) const {
            unordered_set<std::string> validFieldNames;
            validFieldNames.insert("createUser");
            validFieldNames.insert("user");
            validFieldNames.insert("pwd");
            validFieldNames.insert("userSource");
            validFieldNames.insert("roles");
            validFieldNames.insert("readOnly");
            validFieldNames.insert("otherDBRoles");


            // Iterate through all fields in command object and make sure there are no unexpected
            // ones.
            for (BSONObjIterator iter(cmdObj); iter.more(); iter.next()) {
                StringData fieldName = (*iter).fieldNameStringData();
                if (!validFieldNames.count(fieldName.toString())) {
                    return Status(ErrorCodes::BadValue,
                                  mongoutils::str::stream() << "\"" << fieldName << "\" is not "
                                          "a valid argument to createUser");
                }
            }

            Status status = bsonExtractStringField(cmdObj, "user", &parsedArgs->userName);
            if (!status.isOK()) {
                return status;
            }

            if (cmdObj.hasField("pwd")) {
                parsedArgs->hasPassword = true;
                status = bsonExtractStringField(cmdObj, "pwd", &parsedArgs->clearTextPassword);
                if (!status.isOK()) {
                    return status;
                }
            }


            if (cmdObj.hasField("userSource")) {
                parsedArgs->hasUserSource = true;
                status = bsonExtractStringField(cmdObj, "userSource", &parsedArgs->userSource);
                if (!status.isOK()) {
                    return status;
                }
            }

            if (cmdObj.hasField("readOnly")) {
                parsedArgs->hasReadOnly = true;
                status = bsonExtractBooleanField(cmdObj, "readOnly", &parsedArgs->readOnly);
                if (!status.isOK()) {
                    return status;
                }
            }

            if (cmdObj.hasField("extraData")) {
                parsedArgs->hasExtraData = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "extraData", Object, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->extraData = element.Obj();
            }

            if (cmdObj.hasField("roles")) {
                parsedArgs->hasRoles = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "roles", Array, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->roles = BSONArray(element.Obj());
            }

            if (cmdObj.hasField("otherDBRoles")) {
                parsedArgs->hasOtherDBRoles = true;
                BSONElement element;
                status = bsonExtractTypedField(cmdObj, "otherDBRoles", Object, &element);
                if (!status.isOK()) {
                    return status;
                }
                parsedArgs->otherDBRoles = element.Obj();
            }

            if (parsedArgs->hasPassword && parsedArgs->hasUserSource) {
                return Status(ErrorCodes::BadValue,
                              "User objects can't have both 'pwd' and 'userSource'");
            }
            if (!parsedArgs->hasPassword && !parsedArgs->hasUserSource) {
                return Status(ErrorCodes::BadValue,
                              "User objects must have one of 'pwd' and 'userSource'");
            }
            if (parsedArgs->hasRoles && parsedArgs->hasReadOnly) {
                return Status(ErrorCodes::BadValue,
                              "User objects can't have both 'roles' and 'readOnly'");
            }

            return Status::OK();
        }