Exemplo n.º 1
0
    bool BatchedCommandRequest::isValidIndexRequest( string* errMsg ) const {

        string dummy;
        if ( !errMsg )
            errMsg = &dummy;
        dassert( isInsertIndexRequest() );

        if ( sizeWriteOps() != 1 ) {
            *errMsg = "invalid batch request for index creation";
            return false;
        }

        NamespaceString targetNSS( getTargetingNS() );
        if ( !targetNSS.isValid() ) {
            *errMsg = targetNSS.ns() + " is not a valid namespace to index";
            return false;
        }

        NamespaceString reqNSS( getNS() );
        if ( reqNSS.db().compare( targetNSS.db() ) != 0 ) {
            *errMsg = targetNSS.ns() + " namespace is not in the request database "
                      + reqNSS.db().toString();
            return false;
        }

        return true;
    }
Exemplo n.º 2
0
    /**
     * Validate authentication on the server for the given dbname.
     */
    void Tool::auth() {

        if (toolGlobalParams.username.empty()) {
            // Make sure that we don't need authentication to connect to this db
            // findOne throws an AssertionException if it's not authenticated.
            if (toolGlobalParams.coll.size() > 0) {
                // BSONTools don't have a collection
                conn().findOne(getNS(), Query("{}"), 0, QueryOption_SlaveOk);
            }

            return;
        }

        BSONObjBuilder authParams;
        authParams <<
            saslCommandUserDBFieldName << getAuthenticationDatabase() <<
            saslCommandUserFieldName << toolGlobalParams.username <<
            saslCommandPasswordFieldName << toolGlobalParams.password  <<
            saslCommandMechanismFieldName <<
            toolGlobalParams.authenticationMechanism;

        if (!toolGlobalParams.gssapiServiceName.empty()) {
            authParams << saslCommandServiceNameFieldName << toolGlobalParams.gssapiServiceName;
        }

        if (!toolGlobalParams.gssapiHostName.empty()) {
            authParams << saslCommandServiceHostnameFieldName << toolGlobalParams.gssapiHostName;
        }

        _conn->auth(authParams.obj());
    }
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::_targetQuery(
    OperationContext* opCtx, const BSONObj& query, const BSONObj& collation) const {
    if (!_routingInfo->db().primary() && !_routingInfo->cm()) {
        return {ErrorCodes::NamespaceNotFound,
                str::stream() << "could not target query in " << getNS().ns()
                              << "; no metadata found"};
    }

    std::set<ShardId> shardIds;
    if (_routingInfo->cm()) {
        try {
            _routingInfo->cm()->getShardIdsForQuery(opCtx, query, collation, &shardIds);
        } catch (const DBException& ex) {
            return ex.toStatus();
        }
    } else {
        shardIds.insert(_routingInfo->db().primary()->getId());
    }

    std::vector<ShardEndpoint> endpoints;
    for (auto&& shardId : shardIds) {
        const auto version = _routingInfo->cm() ? _routingInfo->cm()->getVersion(shardId)
                                                : ChunkVersion::UNSHARDED();
        endpoints.emplace_back(std::move(shardId), version);
    }

    return endpoints;
}
Exemplo n.º 4
0
    /**
     * Validate authentication on the server for the given dbname.  populates
     * level (if supplied) with the user's credentials.
     */
    void Tool::auth( string dbname, Auth::Level * level ) {

        if ( ! dbname.size() )
            dbname = _db;

        if ( ! ( _username.size() || _password.size() ) ) {
            // Make sure that we don't need authentication to connect to this db
            // findOne throws an AssertionException if it's not authenticated.
            if (_coll.size() > 0) {
                // BSONTools don't have a collection
                conn().findOne(getNS(), Query("{}"), 0, QueryOption_SlaveOk);
            }

            // set write-level access if authentication is disabled
            if ( level != NULL )
                *level = Auth::WRITE;

            return;
        }

        string errmsg;
        if (dbname.size()) {
            if ( _conn->auth( dbname , _username , _password , errmsg, true, level ) ) {
                return;
            }
        }

        // try against the admin db
        if ( _conn->auth( "admin" , _username , _password , errmsg, true, level ) ) {
            return;
        }

        throw UserException( 9997 , (string)"authentication failed: " + errmsg );
    }
Exemplo n.º 5
0
AutoGetCollectionForRead::~AutoGetCollectionForRead() {
    // Report time spent in read lock
    auto currentOp = CurOp::get(_txn);
    Top::get(_txn->getClient()->getServiceContext())
        .record(currentOp->getNS(),
                currentOp->getOp(),
                -1,  // "read locked"
                _timer.micros(),
                currentOp->isCommand());
}
Exemplo n.º 6
0
Arquivo: model.cpp Projeto: fizx/mongo
    void Model::save( bool check ){
        ScopedDbConnection conn( modelServer() );

        BSONObjBuilder b;
        serialize( b );
        
        if ( _id.isEmpty() ){
            OID oid;
            oid.init();
            b.appendOID( "_id" , &oid );
            
            BSONObj o = b.obj();
            conn->insert( getNS() , o );
            _id = o["_id"].wrap().getOwned();

            log(4) << "inserted new model " << getNS() << "  " << o << endl;
        }
        else {
            BSONElement id = _id["_id"];
            b.append( id );

            BSONObjBuilder qb;
            qb.append( id );
            
            BSONObj q = qb.obj();
            BSONObj o = b.obj();

            log(4) << "updated old model" << getNS() << "  " << q << " " << o << endl;

            conn->update( getNS() , q , o );
            
        }
        
        string errmsg = "";
        if ( check )
            errmsg = conn->getLastError();

        conn.done();

        if ( check && errmsg.size() )
            throw UserException( (string)"error on Model::save: " + errmsg );
    }
Exemplo n.º 7
0
AutoStatsTracker::~AutoStatsTracker() {
    auto curOp = CurOp::get(_opCtx);
    Top::get(_opCtx->getServiceContext())
        .record(_opCtx,
                curOp->getNS(),
                curOp->getLogicalOp(),
                _lockType,
                durationCount<Microseconds>(curOp->elapsedTimeExcludingPauses()),
                curOp->isCommand(),
                curOp->getReadWriteType());
}
Exemplo n.º 8
0
OldClientContext::~OldClientContext() {
    // Lock must still be held
    invariant(_txn->lockState()->isLocked());

    auto currentOp = CurOp::get(_txn);
    Top::get(_txn->getClient()->getServiceContext())
        .record(currentOp->getNS(),
                currentOp->getOp(),
                _txn->lockState()->isWriteLocked() ? 1 : -1,
                _timer.micros(),
                currentOp->isCommand());
}
Exemplo n.º 9
0
Arquivo: model.cpp Projeto: fizx/mongo
    bool Model::load(BSONObj& query){
        ScopedDbConnection conn( modelServer() );

        BSONObj b = conn->findOne(getNS(), query);
        conn.done();
        
        if ( b.isEmpty() )
            return false;
        
        unserialize(b);
        _id = b["_id"].wrap().getOwned();
        return true;
    }
Exemplo n.º 10
0
void recordStatsForTopCommand(OperationContext* txn) {
    auto curOp = CurOp::get(txn);
    const int writeLocked = 1;

    Top::get(txn->getClient()->getServiceContext())
        .record(txn,
                curOp->getNS(),
                curOp->getLogicalOp(),
                writeLocked,
                curOp->elapsedMicros(),
                curOp->isCommand(),
                curOp->getReadWriteType());
}
Exemplo n.º 11
0
OldClientContext::~OldClientContext() {
    // Lock must still be held
    invariant(_opCtx->lockState()->isLocked());

    auto currentOp = CurOp::get(_opCtx);
    Top::get(_opCtx->getClient()->getServiceContext())
        .record(_opCtx,
                currentOp->getNS(),
                currentOp->getLogicalOp(),
                _opCtx->lockState()->isWriteLocked() ? Top::LockType::WriteLocked
                                                     : Top::LockType::ReadLocked,
                _timer.micros(),
                currentOp->isCommand(),
                currentOp->getReadWriteType());
}
Exemplo n.º 12
0
    void Model::remove( bool safe ){
        uassert( 10016 ,  "_id isn't set - needed for remove()" , _id["_id"].type() );
        
        ScopedDbConnection conn( modelServer() );
        conn->remove( getNS() , _id );

        string errmsg = "";
        if ( safe )
            errmsg = conn->getLastError();

        conn.done();
        
        if ( safe && errmsg.size() )
            throw UserException( 9002 , (string)"error on Model::remove: " + errmsg );
    }
Exemplo n.º 13
0
    BSONObj ChunkType::toBSON() const {
        BSONObjBuilder builder;
        if (_name) builder.append(name.name(), getName());
        if (_ns) builder.append(ns.name(), getNS());
        if (_min) builder.append(min.name(), getMin());
        if (_max) builder.append(max.name(), getMax());
        if (_shard) builder.append(shard.name(), getShard());
        if (_version) {
            // For now, write both the deprecated *and* the new fields
            _version->addToBSON(builder, version());
            _version->addToBSON(builder, DEPRECATED_lastmod());
        }
        if (_jumbo) builder.append(jumbo.name(), getJumbo());

        return builder.obj();
    }
Exemplo n.º 14
0
Arquivo: tool.cpp Projeto: Ecako/mongo
    /**
     * Validate authentication on the server for the given dbname.
     */
    void Tool::auth() {

        if ( _username.empty() ) {
            // Make sure that we don't need authentication to connect to this db
            // findOne throws an AssertionException if it's not authenticated.
            if (_coll.size() > 0) {
                // BSONTools don't have a collection
                conn().findOne(getNS(), Query("{}"), 0, QueryOption_SlaveOk);
            }

            return;
        }

        _conn->auth( BSON( saslCommandUserSourceFieldName << getAuthenticationDatabase() <<
                           saslCommandUserFieldName << _username <<
                           saslCommandPasswordFieldName << _password  <<
                           saslCommandMechanismFieldName << _authenticationMechanism ) );
    }
Exemplo n.º 15
0
BSONObj ChunkType::toConfigBSON() const {
    BSONObjBuilder builder;
    if (_nss && _min)
        builder.append(name.name(), getName());
    if (_nss)
        builder.append(ns.name(), getNS().ns());
    if (_min)
        builder.append(min.name(), getMin());
    if (_max)
        builder.append(max.name(), getMax());
    if (_shard)
        builder.append(shard.name(), getShard().toString());
    if (_version)
        _version->appendForChunk(&builder);
    if (_jumbo)
        builder.append(jumbo.name(), getJumbo());

    return builder.obj();
}
Exemplo n.º 16
0
BSONObj ChangeLogType::toBSON() const {
    BSONObjBuilder builder;

    if (_changeId)
        builder.append(changeId.name(), getChangeId());
    if (_server)
        builder.append(server.name(), getServer());
    if (_shard)
        builder.append(shard.name(), getShard());
    if (_clientAddr)
        builder.append(clientAddr.name(), getClientAddr());
    if (_time)
        builder.append(time.name(), getTime());
    if (_what)
        builder.append(what.name(), getWhat());
    if (_ns)
        builder.append(ns.name(), getNS());
    if (_details)
        builder.append(details.name(), getDetails());

    return builder.obj();
}
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetCollection() const {
    if (!_routingInfo->db().primary() && !_routingInfo->cm()) {
        return {ErrorCodes::NamespaceNotFound,
                str::stream() << "could not target full range of " << getNS().ns()
                              << "; metadata not found"};
    }

    std::set<ShardId> shardIds;
    if (_routingInfo->cm()) {
        _routingInfo->cm()->getAllShardIds(&shardIds);
    } else {
        shardIds.insert(_routingInfo->db().primary()->getId());
    }

    std::vector<ShardEndpoint> endpoints;
    for (auto&& shardId : shardIds) {
        const auto version = _routingInfo->cm() ? _routingInfo->cm()->getVersion(shardId)
                                                : ChunkVersion::UNSHARDED();
        endpoints.emplace_back(std::move(shardId), version);
    }

    return endpoints;
}
Exemplo n.º 18
0
    void Model::save( bool safe ) {
        scoped_ptr<ScopedDbConnection> conn(
                ScopedDbConnection::getScopedDbConnection (modelServer() ) );

        BSONObjBuilder b;
        serialize( b );

        BSONElement myId;
        {
            BSONObjIterator i = b.iterator();
            while ( i.more() ) {
                BSONElement e = i.next();
                if ( strcmp( e.fieldName() , "_id" ) == 0 ) {
                    myId = e;
                    break;
                }
            }
        }

        if ( myId.type() ) {
            if ( _id.isEmpty() ) {
                _id = myId.wrap();
            }
            else if ( myId.woCompare( _id.firstElement() ) ) {
                stringstream ss;
                ss << "_id from serialize and stored differ: ";
                ss << '[' << myId << "] != ";
                ss << '[' << _id.firstElement() << ']';
                throw UserException( 13121 , ss.str() );
            }
        }

        if ( _id.isEmpty() ) {
            OID oid;
            oid.init();
            b.appendOID( "_id" , &oid );

            BSONObj o = b.obj();
            conn->get()->insert( getNS() , o );
            _id = o["_id"].wrap().getOwned();

            LOG(4) << "inserted new model " << getNS() << "  " << o << endl;
        }
        else {
            if ( myId.eoo() ) {
                myId = _id["_id"];
                b.append( myId );
            }

            verify( ! myId.eoo() );

            BSONObjBuilder qb;
            qb.append( myId );

            BSONObj q = qb.obj();
            BSONObj o = b.obj();

            LOG(4) << "updated model" << getNS() << "  " << q << " " << o << endl;

            conn->get()->update( getNS() , q , o , true );

        }

        string errmsg = "";
        if ( safe )
            errmsg = conn->get()->getLastError();

        conn->done();

        if ( safe && errmsg.size() )
            throw UserException( 9003 , (string)"error on Model::save: " + errmsg );
    }
Exemplo n.º 19
0
 string BatchedCommandRequest::getTargetingNS() const {
     if ( !isInsertIndexRequest() ) return getNS();
     NamespaceString nss;
     extractIndexNSS( getInsertRequest()->getDocumentsAt( 0 ), &nss );
     return nss.toString();
 }
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetAllShards(
    OperationContext* opCtx) const {
    if (!_routingInfo->db().primary() && !_routingInfo->cm()) {
        return {ErrorCodes::NamespaceNotFound,
                str::stream() << "could not target every shard with versions for " << getNS().ns()
                              << "; metadata not found"};
    }

    std::vector<ShardId> shardIds;
    Grid::get(opCtx)->shardRegistry()->getAllShardIdsNoReload(&shardIds);

    std::vector<ShardEndpoint> endpoints;
    for (auto&& shardId : shardIds) {
        const auto version = _routingInfo->cm() ? _routingInfo->cm()->getVersion(shardId)
                                                : ChunkVersion::UNSHARDED();
        endpoints.emplace_back(std::move(shardId), version);
    }

    return endpoints;
}
Exemplo n.º 21
0
 bool BatchedCommandRequest::isInsertIndexRequest() const {
     if ( _batchType != BatchedCommandRequest::BatchType_Insert ) return false;
     return NamespaceString( getNS() ).isSystemDotIndexes();
 }
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetDelete(
    OperationContext* opCtx, const write_ops::DeleteOpEntry& deleteDoc) const {
    BSONObj shardKey;

    if (_routingInfo->cm()) {
        //
        // Sharded collections have the following further requirements for targeting:
        //
        // Limit-1 deletes must be targeted exactly by shard key *or* exact _id
        //

        // Get the shard key
        StatusWith<BSONObj> status =
            _routingInfo->cm()->getShardKeyPattern().extractShardKeyFromQuery(opCtx,
                                                                              deleteDoc.getQ());

        // Bad query
        if (!status.isOK())
            return status.getStatus();

        shardKey = status.getValue();
    }

    const auto collation = write_ops::collationOf(deleteDoc);

    // Target the shard key or delete query
    if (!shardKey.isEmpty()) {
        try {
            return std::vector<ShardEndpoint>{_targetShardKey(shardKey, collation, 0)};
        } catch (const DBException&) {
            // This delete is potentially not constrained to a single shard
        }
    }

    // We failed to target a single shard.

    // Parse delete query.
    auto qr = stdx::make_unique<QueryRequest>(getNS());
    qr->setFilter(deleteDoc.getQ());
    if (!collation.isEmpty()) {
        qr->setCollation(collation);
    }
    const boost::intrusive_ptr<ExpressionContext> expCtx;
    auto cq = CanonicalQuery::canonicalize(opCtx,
                                           std::move(qr),
                                           expCtx,
                                           ExtensionsCallbackNoop(),
                                           MatchExpressionParser::kAllowAllSpecialFeatures);
    if (!cq.isOK()) {
        return cq.getStatus().withContext(str::stream() << "Could not parse delete query "
                                                        << deleteDoc.getQ());
    }

    // Single deletes must target a single shard or be exact-ID.
    if (_routingInfo->cm() && !deleteDoc.getMulti() &&
        !isExactIdQuery(opCtx, *cq.getValue(), _routingInfo->cm().get())) {
        return Status(ErrorCodes::ShardKeyNotFound,
                      str::stream()
                          << "A single delete on a sharded collection must contain an exact "
                             "match on _id (and have the collection default collation) or "
                             "contain the shard key (and have the simple collation). Delete "
                             "request: "
                          << deleteDoc.toBSON()
                          << ", shard key pattern: "
                          << _routingInfo->cm()->getShardKeyPattern().toString());
    }

    return _targetQuery(opCtx, deleteDoc.getQ(), collation);
}
StatusWith<std::vector<ShardEndpoint>> ChunkManagerTargeter::targetUpdate(
    OperationContext* opCtx, const write_ops::UpdateOpEntry& updateDoc) const {
    //
    // Update targeting may use either the query or the update.  This is to support save-style
    // updates, of the form:
    //
    // coll.update({ _id : xxx }, { _id : xxx, shardKey : 1, foo : bar }, { upsert : true })
    //
    // Because drivers do not know the shard key, they can't pull the shard key automatically
    // into the query doc, and to correctly support upsert we must target a single shard.
    //
    // The rule is simple - If the update is replacement style (no '$set'), we target using the
    // update. If the update is not replacement style, we target using the query. Because mongoD
    // will automatically propagate '_id' from an existing document, and will extract it from an
    // exact-match in the query in the case of an upsert, we augment the replacement doc with the
    // query's '_id' for targeting purposes, if it exists.
    //
    // Once we have determined the correct component to target on, we attempt to extract an exact
    // shard key from it. If one is present, we target using it.
    //
    const auto updateType = getUpdateExprType(updateDoc);
    if (!updateType.isOK()) {
        return updateType.getStatus();
    }

    // If the collection is not sharded, forward the update to the primary shard.
    if (!_routingInfo->cm()) {
        if (!_routingInfo->db().primary()) {
            return {ErrorCodes::NamespaceNotFound,
                    str::stream() << "could not target update on " << getNS().ns()
                                  << "; no metadata found"};
        }
        return std::vector<ShardEndpoint>{
            {_routingInfo->db().primaryId(), ChunkVersion::UNSHARDED()}};
    }

    const auto& shardKeyPattern = _routingInfo->cm()->getShardKeyPattern();
    const auto collation = write_ops::collationOf(updateDoc);

    const auto updateExpr = getUpdateExpr(opCtx, shardKeyPattern, updateType.getValue(), updateDoc);
    const bool isUpsert = updateDoc.getUpsert();
    const auto query = updateDoc.getQ();
    if (!updateExpr.isOK()) {
        return updateExpr.getStatus();
    }

    // We first attempt to target by exact match on the shard key.
    const auto swTarget = _targetUpdateByShardKey(
        opCtx, updateType.getValue(), query, collation, updateExpr.getValue(), isUpsert);

    // Return the status if we were successful in targeting by shard key. If this is an upsert, then
    // we return the status regardless of whether or not we succeeded, since an upsert must always
    // target an exact shard key or fail. If this is *not* an upsert and we were unable to target an
    // exact shard key, then we proceed to try other means of targeting the update.
    if (isUpsert || swTarget.isOK()) {
        return swTarget;
    }

    // If we could not target by shard key, attempt to route the update by query or replacement doc.
    auto shardEndPoints = (updateType.getValue() == UpdateType::kOpStyle
                               ? _targetQuery(opCtx, query, collation)
                               : _targetDoc(opCtx, updateExpr.getValue(), collation));

    // Single (non-multi) updates must target a single shard, or an exact _id.
    if (!updateDoc.getMulti() && shardEndPoints.isOK() && shardEndPoints.getValue().size() > 1) {
        if (!isExactIdQuery(opCtx, getNS(), query, collation, _routingInfo->cm().get())) {
            return {ErrorCodes::InvalidOptions,
                    str::stream() << "A {multi:false} update on a sharded collection must either "
                                     "contain an exact match on _id (and have the collection "
                                     "default collation) or must target a single shard (and have "
                                     "the simple collation), but this update targeted "
                                  << shardEndPoints.getValue().size()
                                  << " shards. Update request: "
                                  << updateDoc.toBSON()
                                  << ", shard key pattern: "
                                  << shardKeyPattern.toString()};
        }
    }

    return shardEndPoints;
}
StatusWith<ShardEndpoint> ChunkManagerTargeter::targetInsert(OperationContext* opCtx,
                                                             const BSONObj& doc) const {
    BSONObj shardKey;

    if (_routingInfo->cm()) {
        //
        // Sharded collections have the following requirements for targeting:
        //
        // Inserts must contain the exact shard key.
        //

        shardKey = _routingInfo->cm()->getShardKeyPattern().extractShardKeyFromDoc(doc);

        // Check shard key exists
        if (shardKey.isEmpty()) {
            return {ErrorCodes::ShardKeyNotFound,
                    str::stream() << "document " << doc
                                  << " does not contain shard key for pattern "
                                  << _routingInfo->cm()->getShardKeyPattern().toString()};
        }

        // Check shard key size on insert
        Status status = ShardKeyPattern::checkShardKeySize(shardKey);
        if (!status.isOK())
            return status;
    }

    // Target the shard key or database primary
    if (!shardKey.isEmpty()) {
        return _targetShardKey(shardKey, CollationSpec::kSimpleSpec, doc.objsize());
    } else {
        if (!_routingInfo->db().primary()) {
            return Status(ErrorCodes::NamespaceNotFound,
                          str::stream() << "could not target insert in collection " << getNS().ns()
                                        << "; no metadata found");
        }

        return ShardEndpoint(_routingInfo->db().primary()->getId(), ChunkVersion::UNSHARDED());
    }

    return Status::OK();
}