MongoDB源码分析——mongod数据查询操作

源码版本为MongoDB 2.6分支

Edit

mongod数据查询操作

在mongod的初始化过程中说过,服务端接收到客户端消息后调用MyMessageHandler::process函数处理消息。

class MyMessageHandler : public MessageHandler {
public:
    ...
    virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
        while ( true ) {
            ...

            DbResponse dbresponse;
            try {
                assembleResponse( m, dbresponse, port->remote() );
            }
            catch ( const ClockSkewException & ) {
                log() << "ClockSkewException - shutting down" << endl;
                exitCleanly( EXIT_CLOCK_SKEW );
            }
            ...
        }
    }
};

DbResponse dbresponse;封装了服务器处理消息后的响应数据。在进入数据处理分析之前先看一个枚举类型Operations ,Operations表示了所有MongoDB的操作 类型 :

enum Operations {
    opReply = 1,     /* reply. responseTo is set. */
    dbMsg = 1000,    /* generic msg command followed by a string */
    dbUpdate = 2001, /* update object */
    dbInsert = 2002, //数据插入
    //dbGetByOID = 2003,
    dbQuery = 2004,  //数据查询
    dbGetMore = 2005, //可能是数据同步
    dbDelete = 2006, //数据删除
    dbKillCursors = 2007 //关闭cursor
};

Message对象中封装了当前message的操作类型。之后本篇文章只分析dbQuery 部分,其他部分将会在其他文章中分析。
可以看到process中调用了assembleResponse来处理消息并封装响应对象(DbResponse dbresponse),下面部分我们将分析assembleResponse函数:

int op = m.operation();
    bool isCommand = false;

    DbMessage dbmsg(m);

    if ( op == dbQuery ) {
        const char *ns = dbmsg.getns();

        if (strstr(ns, ".$cmd")) {
            isCommand = true;
            opwrite(m);
            if( strstr(ns, ".$cmd.sys.") ) {
                if( strstr(ns, "$cmd.sys.inprog") ) {
                    inProgCmd(m, dbresponse);
                    return;
                }
                if( strstr(ns, "$cmd.sys.killop") ) {
                    killOp(m, dbresponse);
                    return;
                }
                if( strstr(ns, "$cmd.sys.unlock") ) {
                    unlockFsync(ns, m, dbresponse);
                    return;
                }
            }
        }
        else {
            opread(m); //如果不是命令则记录日志
        }
    }
    ...

在阅读上面的代码之前首先要了解MongoDB源码里面的一个概念——namespace(缩写ns),一个ns代表一个collection和对应的db,一般表示为:”db name” + “.” + “collection name”,如果ns名称中包含“.$cmd”则表示当前操作为一个命令。所以上面代码先判断了是否为数据库命令,如果是则处理,然后返回。

    // Increment op counters.
    switch (op) {
    case dbQuery:
        if (!isCommand) {
            //增加查询操作计数,暂时没发现有什么作用~
            globalOpCounters.gotQuery();
        }
        else {
            // Command counting is deferred, since it is not known yet whether the command
            // needs counting.
        }
        break;
        ...
    }

    ...
    //进入正题,查询数据
    if ( op == dbQuery ) {
        if ( handlePossibleShardedMessage( m , &dbresponse ) )
            return;
        receivedQuery(c , dbresponse, m );
    }

之前的这些代码都只是做了一下操作分发操作,就是把不同的操作请求分配给相应的函数去处理,而查询请求则由receivedQuery函数处理。

static bool receivedQuery(Client& c, DbResponse& dbresponse, Message& m ) {
    ...
    DbMessage d(m);
    QueryMessage q(d);
    auto_ptr< Message > resp( new Message() );

    CurOp& op = *(c.curop());

    try {
        NamespaceString ns(d.getns());
        cout << "receivedQuery NamespaceString : " << d.getns() << endl;

        if (!ns.isCommand()) {
            //查询权限认证
            // Auth checking for Commands happens later.
            Client* client = &cc();
            Status status = client->getAuthorizationSession()->checkAuthForQuery(ns, q.query);
            audit::logQueryAuthzCheck(client, ns, q.query, status.code());
            uassertStatusOK(status);
        }
        dbresponse.exhaustNS = newRunQuery(m, q, op, *resp);
        verify( !resp->empty() );
    }
    catch (...)
    {
        ...
    }
    ...

    return ok;
}

receivedQuery主要分为两部分,第一部分是查询操作,第二部分是操作结果处理(这一部分我给省略了),可以看到,进行查询操作前先进行了查询操作认证,如果当前用户对这个集合没有权限则会抛出异常。如果认证通过则会调用newRunQuery函数进行查询。

/**
  * Run the query 'q' and place the result in 'result'.
  */
std::string newRunQuery(Message& m, QueryMessage& q, CurOp& curop, Message &result);

接下来才是查询操作的重头戏,整个过程包括数据的加载,查询命令解析,集合数据扫描匹配等步骤,由于目前对MongoDB的还不是很熟悉,很多地方我个人还是理解不了,所以具体的数据扫描匹配细节会暂时略过,先分析查找流程,具体细节以后深入之后再学习。

    const NamespaceString nsString(ns);
    uassert(16256, str::stream() << "Invalid ns [" << ns << "]", nsString.isValid());

    // Set curop information.
    curop.debug().ns = ns;
    curop.debug().ntoreturn = q.ntoreturn;
    curop.debug().query = q.query;
    curop.setQuery(q.query);

    // If the query is really a command, run it.
    if (nsString.isCommand()) {
        int nToReturn = q.ntoreturn;
        uassert(16979, str::stream() << "bad numberToReturn (" << nToReturn
                                     << ") for $cmd type ns - can only be 1 or -1",
                nToReturn == 1 || nToReturn == -1);

        curop.markCommand();

        BufBuilder bb;
        bb.skip(sizeof(QueryResult));

        BSONObjBuilder cmdResBuf;
        if (!runCommands(ns, q.query, curop, bb, cmdResBuf, false, q.queryOptions)) {
            uasserted(13530, "bad or malformed command request?");
        }

        curop.debug().iscommand = true;
        // TODO: Does this get overwritten/do we really need to set this twice?
        curop.debug().query = q.query;

        QueryResult* qr = reinterpret_cast<QueryResult*>(bb.buf());
        bb.decouple();
        qr->setResultFlagsToOk();
        qr->len = bb.len();
        curop.debug().responseLength = bb.len();
        qr->setOperation(opReply);
        qr->cursorId = 0;
        qr->startingFrom = 0;
        qr->nReturned = 1;
        result.setData(qr, true);
        return "";
    }

之前的代码中已经对部分killop,unlock等部分命令进行了处理,这个地方对之前没有处理的命令再次进行处理,然后直接返回。如果不是命令则继续往下执行,下面就是整个算法最核心的部分:

    // This is a read lock.  We require this because if we're parsing a $where, the
    // where-specific parsing code assumes we have a lock and creates execution machinery that
    // requires it.
    Client::ReadContext ctx(q.ns);
    Collection* collection = ctx.ctx().db()->getCollection( ns );

    // Parse the qm into a CanonicalQuery.
    CanonicalQuery* cq;
    Status canonStatus = CanonicalQuery::canonicalize(q, &cq);
    if (!canonStatus.isOK()) {
        uasserted(17287, str::stream() << "Can't canonicalize query: " << canonStatus.toString());
    }
    verify(cq);

    QLOG() << "Running query:
" << cq->toString();
    LOG(2) << "Running query: " << cq->toStringShort();

    // Parse, canonicalize, plan, transcribe, and get a runner.
    Runner* rawRunner = NULL;

    // We use this a lot below.
    const LiteParsedQuery& pq = cq->getParsed();

    // We'll now try to get the query runner that will execute this query for us. There
    // are a few cases in which we know upfront which runner we should get and, therefore,
    // we shortcut the selection process here.
    //
    // (a) If the query is over a collection that doesn't exist, we get a special runner
    // that's is so (a runner) which doesn't return results, the EOFRunner.
    //
    // (b) if the query is a replication's initial sync one, we get a SingleSolutinRunner
    // that uses a specifically designed stage that skips extents faster (see details in
    // exec/oplogstart.h)
    //
    // Otherwise we go through the selection of which runner is most suited to the
    // query + run-time context at hand.
    Status status = Status::OK();
    if (collection == NULL) {
        rawRunner = new EOFRunner(cq, cq->ns());
    }
    else if (pq.hasOption(QueryOption_OplogReplay)) {
        status = getOplogStartHack(collection, cq, &rawRunner);
    }
    else {
        // Takes ownership of cq.
        size_t options = QueryPlannerParams::DEFAULT;
        if (shardingState.needCollectionMetadata(pq.ns())) {
            options |= QueryPlannerParams::INCLUDE_SHARD_FILTER;
        }
        status = getRunner(cq, &rawRunner, options);
    }

    if (!status.isOK()) {
        // NOTE: Do not access cq as getRunner has deleted it.
        uasserted(17007, "Unable to execute query: " + status.reason());
    }

上面部分代码包含数据加载,查询数据解析,查询算法匹配等过程,下面稍微详细的分析一下过程。

    // This is a read lock.  We require this because if we're parsing a $where, the
    // where-specific parsing code assumes we have a lock and creates execution machinery that
    // requires it.
    Client::ReadContext ctx(q.ns);

从注释中可以看着,这是一个“读锁”,但是他实际的功能并不止这些。

 /** "read lock, and set my context, all in one operation" 
     *  This handles (if not recursively locked) opening an unopened database.
     */
    class ReadContext : boost::noncopyable { 
    public:
        ReadContext(const std::string& ns, const std::string& path=storageGlobalParams.dbpath);
        Context& ctx() { return *c.get(); }
    private:
        scoped_ptr<Lock::DBRead> lk;
        scoped_ptr<Context> c;
    };

ReadContext 有点像一个代理或者是适配器,实际包含了一个Context对象,然后利用Lock::DBRead添加“读锁”操作。

/** "read lock, and set my context, all in one operation" 
 *  This handles (if not recursively locked) opening an unopened database.
 */
Client::ReadContext::ReadContext(const string& ns, const std::string& path) {
    {
        lk.reset( new Lock::DBRead(ns) );
        Database *db = dbHolder().get(ns, path);
        if( db ) {
            c.reset( new Context(path, ns, db) );
            return;
        }
    }

    // we usually don't get here, so doesn't matter how fast this part is
    {
        if( Lock::isW() ) { 
            // write locked already
            DEV RARELY log() << "write locked on ReadContext construction " << ns << endl;
            c.reset(new Context(ns, path));
        }
        else if( !Lock::nested() ) { 
            lk.reset(0);
            {
                Lock::GlobalWrite w;
                Context c(ns, path);
            }
            // db could be closed at this interim point -- that is ok, we will throw, and don't mind throwing.
            lk.reset( new Lock::DBRead(ns) );
            c.reset(new Context(ns, path));
        }
        else { 
            uasserted(15928, str::stream() << "can't open a database from a nested read lock " << ns);
        }
    }
}

可以看到在ReadContext构造函数中先根据ns来锁住数据库(之前已经说过,ns包含数据库名称和集合名称),然后在根据ns和数据库路径来获取Database对象,一个Database对象代表一个数据库(这部分包含数据库数据加载,暂时不分析),如果获取到db对象,则设置上下文信息。

如果没有获取到db对象,则会进入到下面:

lk.reset( new Lock::DBRead(ns) );
c.reset(new Context(ns, path));

Context提供了多个构造函数,这个构造函数中会去创建db对象,并加载数据。锁住数据库之后将进入核心查询部分。

 // Parse the qm into a CanonicalQuery.
    CanonicalQuery* cq;
    Status canonStatus = CanonicalQuery::canonicalize(q, &cq);

首先会解析查询消息为标准化的查询对象,主要是将BSON结构数据转换为MatchExpression方便使用。
之后会获取一个Runner对象来执行查询:

    Runner* rawRunner = NULL;

    // We use this a lot below.
    const LiteParsedQuery& pq = cq->getParsed();

    // We'll now try to get the query runner that will execute this query for us. There
    // are a few cases in which we know upfront which runner we should get and, therefore,
    // we shortcut the selection process here.
    //
    // (a) If the query is over a collection that doesn't exist, we get a special runner
    // that's is so (a runner) which doesn't return results, the EOFRunner.
    //
    // (b) if the query is a replication's initial sync one, we get a SingleSolutinRunner
    // that uses a specifically designed stage that skips extents faster (see details in
    // exec/oplogstart.h)
    //
    // Otherwise we go through the selection of which runner is most suited to the
    // query + run-time context at hand.
    Status status = Status::OK();
    if (collection == NULL) {
        rawRunner = new EOFRunner(cq, cq->ns());
    }
    else if (pq.hasOption(QueryOption_OplogReplay)) {
        status = getOplogStartHack(collection, cq, &rawRunner);
    }
    else {
        // Takes ownership of cq.
        size_t options = QueryPlannerParams::DEFAULT;
        if (shardingState.needCollectionMetadata(pq.ns())) {
            options |= QueryPlannerParams::INCLUDE_SHARD_FILTER;
        }
        status = getRunner(cq, &rawRunner, options);
    }

上面代码调用getRunner函数来返回一个Runner对象,该Runner对象会对集合进行遍历,然后找到符合查询条件的结果并返回。

一个Runner就代表一种数据查询方式,mongo会根据之前的查询BSON解析结果来判断应该使用哪一种Runner来执行查询,有点类似策略模式。
IDHackRunner : 当前集合是以“_id”作为索引或者查询条件中包含”_id”时就使用此来查询。
CachedPlanRunner:如果之前已经有缓存plan,则使用此来查询。
MultiPlanRunner:使用QueryPlanner来plan 查询条件,如果结果为多个QuerySolution,则使用此来执行查询。
SingleSolutionRunner:和multi相对应,对应一些简单的查询则使用此来执行。
SubPlanRunner:没搞明白…

上面这些Runner都比较复杂,详细分析的话每一个都能需要耗费很多时间,其中包含了对集合的扫描算法,对查询的分段处理等等,整个mongod的核心查询算法都封装在这里面,暂时就不深入研究了。

    // Run the query.
    // bb is used to hold query results
    // this buffer should contain either requested documents per query or
    // explain information, but not both
    BufBuilder bb(32768);
    bb.skip(sizeof(QueryResult));

      ...

    while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&obj, NULL))) {
        // Add result to output buffer. This is unnecessary if explain info is requested
        if (!isExplain) {
            bb.appendBuf((void*)obj.objdata(), obj.objsize());
        }

        // Count the result.
        ++numResults;
        ...
    }

获取Runner对象后当然是使用该对象来获取查询结果,Runner提供一个getNext函数来获取下一个结果,之后的就是将查询结果放到result中,然后返回给客户端。

至此,整个数据查询的轮廓已经出来了,其中数据加载和查询算法部分我都很只是提了一下然后略过,主要是水平有限,很多东西我自己还没弄明白,写出来也都是错的,MongoDB的每一个版本代码改动都很大,参考了很多前辈对其他版本的分析,真是很佩服他们,很多东西都分析很透彻,但是对照来看这个版本的源码还是有很多迷惑的地方,所以数据加载和查询算法两个部分之研究明白之后再单独开篇吧。

 
%23%23%20mongod%u6570%u636E%u67E5%u8BE2%u64CD%u4F5C%0A%u5728mongod%u7684%u521D%u59CB%u5316%u8FC7%u7A0B%u4E2D%u8BF4%u8FC7%uFF0C%u670D%u52A1%u7AEF%u63A5%u6536%u5230%u5BA2%u6237%u7AEF%u6D88%u606F%u540E%u8C03%u7528MyMessageHandler%3A%3Aprocess%u51FD%u6570%u5904%u7406%u6D88%u606F%u3002%0A%0A%20%20%20%20class%20MyMessageHandler%20%3A%20public%20MessageHandler%20%7B%0A%20%20%20%20public%3A%0A%09%20%20%20%20...%0A%20%20%20%20%20%20%20%20virtual%20void%20process%28%20Message%26%20m%20%2C%20AbstractMessagingPort*%20port%20%2C%20LastError%20*%20le%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20%28%20true%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DbResponse%20dbresponse%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20assembleResponse%28%20m%2C%20dbresponse%2C%20port-%3Eremote%28%29%20%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%20%28%20const%20ClockSkewException%20%26%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log%28%29%20%3C%3C%20%22ClockSkewException%20-%20shutting%20down%22%20%3C%3C%20endl%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exitCleanly%28%20EXIT_CLOCK_SKEW%20%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3B%0A%0A%20DbResponse%20dbresponse%3B%u5C01%u88C5%u4E86%u670D%u52A1%u5668%u5904%u7406%u6D88%u606F%u540E%u7684%u54CD%u5E94%u6570%u636E%u3002%u5728%u8FDB%u5165%u6570%u636E%u5904%u7406%u5206%u6790%u4E4B%u524D%u5148%u770B%u4E00%u4E2A%u679A%u4E3E%u7C7B%u578BOperations%20%uFF0COperations%u8868%u793A%u4E86%u6240%u4EE5MongoDB%u7684%u64CD%u4F5C%20%u7C7B%u578B%20%3A%20%0A%0A%20%20%20%20enum%20Operations%20%7B%0A%20%20%20%20%20%20%20%20opReply%20%3D%201%2C%20%20%20%20%20/*%20reply.%20responseTo%20is%20set.%20*/%0A%20%20%20%20%20%20%20%20dbMsg%20%3D%201000%2C%20%20%20%20/*%20generic%20msg%20command%20followed%20by%20a%20string%20*/%0A%20%20%20%20%20%20%20%20dbUpdate%20%3D%202001%2C%20/*%20update%20object%20*/%0A%20%20%20%20%20%20%20%20dbInsert%20%3D%202002%2C%20//%u6570%u636E%u63D2%u5165%0A%20%20%20%20%20%20%20%20//dbGetByOID%20%3D%202003%2C%0A%20%20%20%20%20%20%20%20dbQuery%20%3D%202004%2C%20%20//%u6570%u636E%u67E5%u8BE2%0A%20%20%20%20%20%20%20%20dbGetMore%20%3D%202005%2C%20//%u53EF%u80FD%u662F%u6570%u636E%u540C%u6B65%0A%20%20%20%20%20%20%20%20dbDelete%20%3D%202006%2C%20//%u6570%u636E%u5220%u9664%0A%20%20%20%20%20%20%20%20dbKillCursors%20%3D%202007%20//%u5173%u95EDcursor%0A%20%20%20%20%7D%3B%0AMessage%u5BF9%u8C61%u4E2D%u5C01%u88C5%u4E86%u5F53%u524Dmessage%u7684%u64CD%u4F5C%u7C7B%u578B%u3002%u4E4B%u540E%u672C%u7BC7%u6587%u7AE0%u53EA%u5206%u6790dbQuery%20%u90E8%u5206%uFF0C%u5176%u4ED6%u90E8%u5206%u5C06%u4F1A%u5728%u5176%u4ED6%u6587%u7AE0%u4E2D%u5206%u6790%u3002%0A%u53EF%u4EE5%u770B%u5230process%u4E2D%u8C03%u7528%u4E86assembleResponse%u6765%u5904%u7406%u6D88%u606F%u5E76%u5C01%u88C5%u54CD%u5E94%u5BF9%u8C61%uFF08DbResponse%20dbresponse%uFF09%2C%u4E0B%u9762%u90E8%u5206%u6211%u4EEC%u5C06%u5206%u6790assembleResponse%u51FD%u6570%3A%0A%0A%20%20%20%20int%20op%20%3D%20m.operation%28%29%3B%0A%20%20%20%20%20%20%20%20bool%20isCommand%20%3D%20false%3B%0A%0A%20%20%20%20%20%20%20%20DbMessage%20dbmsg%28m%29%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20if%20%28%20op%20%3D%3D%20dbQuery%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20char%20*ns%20%3D%20dbmsg.getns%28%29%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28strstr%28ns%2C%20%22.%24cmd%22%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20isCommand%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20opwrite%28m%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%28%20strstr%28ns%2C%20%22.%24cmd.sys.%22%29%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%28%20strstr%28ns%2C%20%22%24cmd.sys.inprog%22%29%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inProgCmd%28m%2C%20dbresponse%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%28%20strstr%28ns%2C%20%22%24cmd.sys.killop%22%29%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20killOp%28m%2C%20dbresponse%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%28%20strstr%28ns%2C%20%22%24cmd.sys.unlock%22%29%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20unlockFsync%28ns%2C%20m%2C%20dbresponse%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20opread%28m%29%3B%20//%u5982%u679C%u4E0D%u662F%u547D%u4EE4%u5219%u8BB0%u5F55%u65E5%u5FD7%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20...%0A%u5728%u9605%u8BFB%u4E0A%u9762%u7684%u4EE3%u7801%u4E4B%u524D%u9996%u5148%u8981%u4E86%u89E3MongoDB%u6E90%u7801%u91CC%u9762%u7684%u4E00%u4E2A%u6982%u5FF5%u2014%u2014namespace%28%u7F29%u5199ns%29%uFF0C%u4E00%u4E2Ans%u4EE3%u8868%u4E00%u4E2Acollection%u548C%u5BF9%u5E94%u7684db%uFF0C%u4E00%u822C%u8868%u793A%u4E3A%3A%22db%20name%22%20+%20%22.%22%20+%20%22collection%20name%22%uFF0C%u5982%u679Cns%u540D%u79F0%u4E2D%u5305%u542B%u201C.%24cmd%u201D%u5219%u8868%u793A%u5F53%u524D%u64CD%u4F5C%u4E3A%u4E00%u4E2A%u547D%u4EE4%u3002%u6240%u4EE5%u4E0A%u9762%u4EE3%u7801%u5148%u5224%u65AD%u4E86%u662F%u5426%u4E3A%u6570%u636E%u5E93%u547D%u4EE4%uFF0C%u5982%u679C%u662F%u5219%u5904%u7406%uFF0C%u7136%u540E%u8FD4%u56DE%u3002%0A%0A%20%20%20%20%20%20%20%20//%20Increment%20op%20counters.%0A%20%20%20%20%20%20%20%20switch%20%28op%29%20%7B%0A%20%20%20%20%20%20%20%20case%20dbQuery%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28%21isCommand%29%20%7B%0A%09%20%20%20%20%20%20%20%20%20%20%20%20//%u589E%u52A0%u67E5%u8BE2%u64CD%u4F5C%u8BA1%u6570%uFF0C%u6682%u65F6%u6CA1%u53D1%u73B0%u6709%u4EC0%u4E48%u4F5C%u7528%7E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20globalOpCounters.gotQuery%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20Command%20counting%20is%20deferred%2C%20since%20it%20is%20not%20known%20yet%20whether%20the%20command%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20needs%20counting.%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%09%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20...%0A%09%09//%u8FDB%u5165%u6B63%u9898%uFF0C%u67E5%u8BE2%u6570%u636E%0A%20%20%20%20%20%20%20%20if%20%28%20op%20%3D%3D%20dbQuery%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28%20handlePossibleShardedMessage%28%20m%20%2C%20%26dbresponse%20%29%20%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20receivedQuery%28c%20%2C%20dbresponse%2C%20m%20%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%u4E4B%u524D%u7684%u8FD9%u4E9B%u4EE3%u7801%u90FD%u53EA%u662F%u505A%u4E86%u4E00%u4E0B%u64CD%u4F5C%u5206%u53D1%u64CD%u4F5C%uFF0C%u5C31%u662F%u628A%u4E0D%u540C%u7684%u64CD%u4F5C%u8BF7%u6C42%u5206%u914D%u7ED9%u76F8%u5E94%u7684%u51FD%u6570%u53BB%u5904%u7406%uFF0C%u800C%u67E5%u8BE2%u8BF7%u6C42%u5219%u7531receivedQuery%u51FD%u6570%u5904%u7406%u3002%0A%0A%20%20%20%20static%20bool%20receivedQuery%28Client%26%20c%2C%20DbResponse%26%20dbresponse%2C%20Message%26%20m%20%29%20%7B%0A%09%20%20%20%20...%0A%20%20%20%20%20%20%20%20DbMessage%20d%28m%29%3B%0A%20%20%20%20%20%20%20%20QueryMessage%20q%28d%29%3B%0A%20%20%20%20%20%20%20%20auto_ptr%3C%20Message%20%3E%20resp%28%20new%20Message%28%29%20%29%3B%0A%0A%20%20%20%20%20%20%20%20CurOp%26%20op%20%3D%20*%28c.curop%28%29%29%3B%0A%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20NamespaceString%20ns%28d.getns%28%29%29%3B%0A%09%09%09cout%20%3C%3C%20%22receivedQuery%20NamespaceString%20%3A%20%22%20%3C%3C%20d.getns%28%29%20%3C%3C%20endl%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28%21ns.isCommand%28%29%29%20%7B%0A%09%20%20%20%20%20%20%20%20%20%20%20%20//%u67E5%u8BE2%u6743%u9650%u8BA4%u8BC1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20Auth%20checking%20for%20Commands%20happens%20later.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Client*%20client%20%3D%20%26cc%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Status%20status%20%3D%20client-%3EgetAuthorizationSession%28%29-%3EcheckAuthForQuery%28ns%2C%20q.query%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20audit%3A%3AlogQueryAuthzCheck%28client%2C%20ns%2C%20q.query%2C%20status.code%28%29%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uassertStatusOK%28status%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20dbresponse.exhaustNS%20%3D%20newRunQuery%28m%2C%20q%2C%20op%2C%20*resp%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20verify%28%20%21resp-%3Eempty%28%29%20%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20catch%20%28...%29%0A%20%20%20%20%20%20%20%20%7B%0A%09%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20...%0A%0A%20%20%20%20%20%20%20%20return%20ok%3B%0A%20%20%20%20%7D%0AreceivedQuery%u4E3B%u8981%u5206%u4E3A%u4E24%u90E8%u5206%uFF0C%u7B2C%u4E00%u90E8%u5206%u662F%u67E5%u8BE2%u64CD%u4F5C%uFF0C%u7B2C%u4E8C%u90E8%u5206%u662F%u64CD%u4F5C%u7ED3%u679C%u5904%u7406%28%u8FD9%u4E00%u90E8%u5206%u6211%u7ED9%u7701%u7565%u4E86%29%uFF0C%u53EF%u4EE5%u770B%u5230%uFF0C%u8FDB%u884C%u67E5%u8BE2%u64CD%u4F5C%u524D%u5148%u8FDB%u884C%u4E86%u67E5%u8BE2%u64CD%u4F5C%u8BA4%u8BC1%uFF0C%u5982%u679C%u5F53%u524D%u7528%u6237%u5BF9%u8FD9%u4E2A%u96C6%u5408%u6CA1%u6709%u6743%u9650%u5219%u4F1A%u629B%u51FA%u5F02%u5E38%u3002%u5982%u679C%u8BA4%u8BC1%u901A%u8FC7%u5219%u4F1A%u8C03%u7528newRunQuery%u51FD%u6570%u8FDB%u884C%u67E5%u8BE2%u3002%0A%0A%20%20%20%20/**%0A%20%20%20%20%20%20*%20Run%20the%20query%20%27q%27%20and%20place%20the%20result%20in%20%27result%27.%0A%20%20%20%20%20%20*/%0A%20%20%20%20std%3A%3Astring%20newRunQuery%28Message%26%20m%2C%20QueryMessage%26%20q%2C%20CurOp%26%20curop%2C%20Message%20%26result%29%3B%0A%u63A5%u4E0B%u6765%u624D%u662F%u67E5%u8BE2%u64CD%u4F5C%u7684%u91CD%u5934%u620F%uFF0C%u6574%u4E2A%u8FC7%u7A0B%u5305%u62EC%u6570%u636E%u7684%u52A0%u8F7D%uFF0C%u67E5%u8BE2%u547D%u4EE4%u89E3%u6790%uFF0C%u96C6%u5408%u6570%u636E%u626B%u63CF%u5339%u914D%u7B49%u6B65%u9AA4%uFF0C%u7531%u4E8E%u76EE%u524D%u5BF9MongoDB%u7684%u8FD8%u4E0D%u662F%u5F88%u719F%u6089%uFF0C%u5F88%u591A%u5730%u65B9%u6211%u4E2A%u4EBA%u8FD8%u662F%u7406%u89E3%u4E0D%u4E86%uFF0C%u6240%u4EE5%u5177%u4F53%u7684%u6570%u636E%u626B%u63CF%u5339%u914D%u7EC6%u8282%u4F1A%u6682%u65F6%u7565%u8FC7%uFF0C%u5148%u5206%u6790%u67E5%u627E%u6D41%u7A0B%uFF0C%u5177%u4F53%u7EC6%u8282%u4EE5%u540E%u6DF1%u5165%u4E4B%u540E%u518D%u5B66%u4E60%u3002%0A%0A%09%20%20%20%20const%20NamespaceString%20nsString%28ns%29%3B%0A%20%20%20%20%20%20%20%20uassert%2816256%2C%20str%3A%3Astream%28%29%20%3C%3C%20%22Invalid%20ns%20%5B%22%20%3C%3C%20ns%20%3C%3C%20%22%5D%22%2C%20nsString.isValid%28%29%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20Set%20curop%20information.%0A%20%20%20%20%20%20%20%20curop.debug%28%29.ns%20%3D%20ns%3B%0A%20%20%20%20%20%20%20%20curop.debug%28%29.ntoreturn%20%3D%20q.ntoreturn%3B%0A%20%20%20%20%20%20%20%20curop.debug%28%29.query%20%3D%20q.query%3B%0A%20%20%20%20%20%20%20%20curop.setQuery%28q.query%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20If%20the%20query%20is%20really%20a%20command%2C%20run%20it.%0A%20%20%20%20%20%20%20%20if%20%28nsString.isCommand%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20nToReturn%20%3D%20q.ntoreturn%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20uassert%2816979%2C%20str%3A%3Astream%28%29%20%3C%3C%20%22bad%20numberToReturn%20%28%22%20%3C%3C%20nToReturn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%3C%20%22%29%20for%20%24cmd%20type%20ns%20-%20can%20only%20be%201%20or%20-1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nToReturn%20%3D%3D%201%20%7C%7C%20nToReturn%20%3D%3D%20-1%29%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20curop.markCommand%28%29%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20BufBuilder%20bb%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20bb.skip%28sizeof%28QueryResult%29%29%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20BSONObjBuilder%20cmdResBuf%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28%21runCommands%28ns%2C%20q.query%2C%20curop%2C%20bb%2C%20cmdResBuf%2C%20false%2C%20q.queryOptions%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uasserted%2813530%2C%20%22bad%20or%20malformed%20command%20request%3F%22%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20curop.debug%28%29.iscommand%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20TODO%3A%20Does%20this%20get%20overwritten/do%20we%20really%20need%20to%20set%20this%20twice%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20curop.debug%28%29.query%20%3D%20q.query%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20QueryResult*%20qr%20%3D%20reinterpret_cast%3CQueryResult*%3E%28bb.buf%28%29%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20bb.decouple%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3EsetResultFlagsToOk%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3Elen%20%3D%20bb.len%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20curop.debug%28%29.responseLength%20%3D%20bb.len%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3EsetOperation%28opReply%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3EcursorId%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3EstartingFrom%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20qr-%3EnReturned%20%3D%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20result.setData%28qr%2C%20true%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%22%22%3B%0A%20%20%20%20%20%20%20%20%7D%0A%u4E4B%u524D%u7684%u4EE3%u7801%u4E2D%u5DF2%u7ECF%u5BF9%u90E8%u5206killop%uFF0Cunlock%u7B49%u90E8%u5206%u547D%u4EE4%u8FDB%u884C%u4E86%u5904%u7406%uFF0C%u8FD9%u4E2A%u5730%u65B9%u5BF9%u4E4B%u524D%u6CA1%u6709%u5904%u7406%u7684%u547D%u4EE4%u518D%u6B21%u8FDB%u884C%u5904%u7406%uFF0C%u7136%u540E%u76F4%u63A5%u8FD4%u56DE%u3002%u5982%u679C%u4E0D%u662F%u547D%u4EE4%u5219%u7EE7%u7EED%u5F80%u4E0B%u6267%u884C%uFF0C%u4E0B%u9762%u5C31%u662F%u6574%u4E2A%u7B97%u6CD5%u6700%u6838%u5FC3%u7684%u90E8%u5206%3A%0A%0A%20%20%20%20%20%20%20%20//%20This%20is%20a%20read%20lock.%20%20We%20require%20this%20because%20if%20we%27re%20parsing%20a%20%24where%2C%20the%0A%20%20%20%20%20%20%20%20//%20where-specific%20parsing%20code%20assumes%20we%20have%20a%20lock%20and%20creates%20execution%20machinery%20that%0A%20%20%20%20%20%20%20%20//%20requires%20it.%0A%20%20%20%20%20%20%20%20Client%3A%3AReadContext%20ctx%28q.ns%29%3B%0A%20%20%20%20%20%20%20%20Collection*%20collection%20%3D%20ctx.ctx%28%29.db%28%29-%3EgetCollection%28%20ns%20%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20Parse%20the%20qm%20into%20a%20CanonicalQuery.%0A%20%20%20%20%20%20%20%20CanonicalQuery*%20cq%3B%0A%20%20%20%20%20%20%20%20Status%20canonStatus%20%3D%20CanonicalQuery%3A%3Acanonicalize%28q%2C%20%26cq%29%3B%0A%20%20%20%20%20%20%20%20if%20%28%21canonStatus.isOK%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20uasserted%2817287%2C%20str%3A%3Astream%28%29%20%3C%3C%20%22Can%27t%20canonicalize%20query%3A%20%22%20%3C%3C%20canonStatus.toString%28%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20verify%28cq%29%3B%0A%0A%20%20%20%20%20%20%20%20QLOG%28%29%20%3C%3C%20%22Running%20query%3A%5Cn%22%20%3C%3C%20cq-%3EtoString%28%29%3B%0A%20%20%20%20%20%20%20%20LOG%282%29%20%3C%3C%20%22Running%20query%3A%20%22%20%3C%3C%20cq-%3EtoStringShort%28%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20Parse%2C%20canonicalize%2C%20plan%2C%20transcribe%2C%20and%20get%20a%20runner.%0A%20%20%20%20%20%20%20%20Runner*%20rawRunner%20%3D%20NULL%3B%0A%0A%20%20%20%20%20%20%20%20//%20We%20use%20this%20a%20lot%20below.%0A%20%20%20%20%20%20%20%20const%20LiteParsedQuery%26%20pq%20%3D%20cq-%3EgetParsed%28%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20We%27ll%20now%20try%20to%20get%20the%20query%20runner%20that%20will%20execute%20this%20query%20for%20us.%20There%0A%20%20%20%20%20%20%20%20//%20are%20a%20few%20cases%20in%20which%20we%20know%20upfront%20which%20runner%20we%20should%20get%20and%2C%20therefore%2C%0A%20%20%20%20%20%20%20%20//%20we%20shortcut%20the%20selection%20process%20here.%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20%28a%29%20If%20the%20query%20is%20over%20a%20collection%20that%20doesn%27t%20exist%2C%20we%20get%20a%20special%20runner%0A%20%20%20%20%20%20%20%20//%20that%27s%20is%20so%20%28a%20runner%29%20which%20doesn%27t%20return%20results%2C%20the%20EOFRunner.%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20%28b%29%20if%20the%20query%20is%20a%20replication%27s%20initial%20sync%20one%2C%20we%20get%20a%20SingleSolutinRunner%0A%20%20%20%20%20%20%20%20//%20that%20uses%20a%20specifically%20designed%20stage%20that%20skips%20extents%20faster%20%28see%20details%20in%0A%20%20%20%20%20%20%20%20//%20exec/oplogstart.h%29%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20Otherwise%20we%20go%20through%20the%20selection%20of%20which%20runner%20is%20most%20suited%20to%20the%0A%20%20%20%20%20%20%20%20//%20query%20+%20run-time%20context%20at%20hand.%0A%20%20%20%20%20%20%20%20Status%20status%20%3D%20Status%3A%3AOK%28%29%3B%0A%20%20%20%20%20%20%20%20if%20%28collection%20%3D%3D%20NULL%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20rawRunner%20%3D%20new%20EOFRunner%28cq%2C%20cq-%3Ens%28%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20if%20%28pq.hasOption%28QueryOption_OplogReplay%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20status%20%3D%20getOplogStartHack%28collection%2C%20cq%2C%20%26rawRunner%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Takes%20ownership%20of%20cq.%0A%20%20%20%20%20%20%20%20%20%20%20%20size_t%20options%20%3D%20QueryPlannerParams%3A%3ADEFAULT%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28shardingState.needCollectionMetadata%28pq.ns%28%29%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20options%20%7C%3D%20QueryPlannerParams%3A%3AINCLUDE_SHARD_FILTER%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20status%20%3D%20getRunner%28cq%2C%20%26rawRunner%2C%20options%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if%20%28%21status.isOK%28%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20NOTE%3A%20Do%20not%20access%20cq%20as%20getRunner%20has%20deleted%20it.%0A%20%20%20%20%20%20%20%20%20%20%20%20uasserted%2817007%2C%20%22Unable%20to%20execute%20query%3A%20%22%20+%20status.reason%28%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%u4E0A%u9762%u90E8%u5206%u4EE3%u7801%u5305%u542B%u6570%u636E%u52A0%u8F7D%uFF0C%u67E5%u8BE2%u6570%u636E%u89E3%u6790%uFF0C%u67E5%u8BE2%u7B97%u6CD5%u5339%u914D%u7B49%u8FC7%u7A0B%uFF0C%u4E0B%u9762%u7A0D%u5FAE%u8BE6%u7EC6%u7684%u5206%u6790%u4E00%u4E0B%u8FC7%u7A0B%u3002%0A%0A%09%20%20%20%20//%20This%20is%20a%20read%20lock.%20%20We%20require%20this%20because%20if%20we%27re%20parsing%20a%20%24where%2C%20the%0A%20%20%20%20%20%20%20%20//%20where-specific%20parsing%20code%20assumes%20we%20have%20a%20lock%20and%20creates%20execution%20machinery%20that%0A%20%20%20%20%20%20%20%20//%20requires%20it.%0A%20%20%20%20%20%20%20%20Client%3A%3AReadContext%20ctx%28q.ns%29%3B%0A%u4ECE%u6CE8%u91CA%u4E2D%u53EF%u4EE5%u770B%u7740%uFF0C%u8FD9%u662F%u4E00%u4E2A%u201C%u8BFB%u9501%u201D%uFF0C%u4F46%u662F%u4ED6%u5B9E%u9645%u7684%u529F%u80FD%u5E76%u4E0D%u6B62%u8FD9%u4E9B%u3002%0A%0A%20%20%20%20%20/**%20%22read%20lock%2C%20and%20set%20my%20context%2C%20all%20in%20one%20operation%22%20%0A%20%20%20%20%20%20%20%20%20*%20%20This%20handles%20%28if%20not%20recursively%20locked%29%20opening%20an%20unopened%20database.%0A%20%20%20%20%20%20%20%20%20*/%0A%20%20%20%20%20%20%20%20class%20ReadContext%20%3A%20boost%3A%3Anoncopyable%20%7B%20%0A%20%20%20%20%20%20%20%20public%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ReadContext%28const%20std%3A%3Astring%26%20ns%2C%20const%20std%3A%3Astring%26%20path%3DstorageGlobalParams.dbpath%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Context%26%20ctx%28%29%20%7B%20return%20*c.get%28%29%3B%20%7D%0A%20%20%20%20%20%20%20%20private%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20scoped_ptr%3CLock%3A%3ADBRead%3E%20lk%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20scoped_ptr%3CContext%3E%20c%3B%0A%20%20%20%20%20%20%20%20%7D%3B%0AReadContext%20%u6709%u70B9%u50CF%u4E00%u4E2A%u4EE3%u7406%u6216%u8005%u662F%u9002%u914D%u5668%uFF0C%u5B9E%u9645%u5305%u542B%u4E86%u4E00%u4E2AContext%u5BF9%u8C61%uFF0C%u7136%u540E%u5229%u7528Lock%3A%3ADBRead%u6DFB%u52A0%u201C%u8BFB%u9501%u201D%u64CD%u4F5C%u3002%0A%0A%20%20%20%20/**%20%22read%20lock%2C%20and%20set%20my%20context%2C%20all%20in%20one%20operation%22%20%0A%20%20%20%20%20*%20%20This%20handles%20%28if%20not%20recursively%20locked%29%20opening%20an%20unopened%20database.%0A%20%20%20%20%20*/%0A%20%20%20%20Client%3A%3AReadContext%3A%3AReadContext%28const%20string%26%20ns%2C%20const%20std%3A%3Astring%26%20path%29%20%7B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20lk.reset%28%20new%20Lock%3A%3ADBRead%28ns%29%20%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Database%20*db%20%3D%20dbHolder%28%29.get%28ns%2C%20path%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%28%20db%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.reset%28%20new%20Context%28path%2C%20ns%2C%20db%29%20%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20//%20we%20usually%20don%27t%20get%20here%2C%20so%20doesn%27t%20matter%20how%20fast%20this%20part%20is%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%28%20Lock%3A%3AisW%28%29%20%29%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20write%20locked%20already%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DEV%20RARELY%20log%28%29%20%3C%3C%20%22write%20locked%20on%20ReadContext%20construction%20%22%20%3C%3C%20ns%20%3C%3C%20endl%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.reset%28new%20Context%28ns%2C%20path%29%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20if%28%20%21Lock%3A%3Anested%28%29%20%29%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lk.reset%280%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Lock%3A%3AGlobalWrite%20w%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Context%20c%28ns%2C%20path%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20db%20could%20be%20closed%20at%20this%20interim%20point%20--%20that%20is%20ok%2C%20we%20will%20throw%2C%20and%20don%27t%20mind%20throwing.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lk.reset%28%20new%20Lock%3A%3ADBRead%28ns%29%20%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.reset%28new%20Context%28ns%2C%20path%29%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uasserted%2815928%2C%20str%3A%3Astream%28%29%20%3C%3C%20%22can%27t%20open%20a%20database%20from%20a%20nested%20read%20lock%20%22%20%3C%3C%20ns%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%u53EF%u4EE5%u770B%u5230%u5728ReadContext%u6784%u9020%u51FD%u6570%u4E2D%u5148%u6839%u636Ens%u6765%u9501%u4F4F%u6570%u636E%u5E93%28%u4E4B%u524D%u5DF2%u7ECF%u8BF4%u8FC7%uFF0Cns%u5305%u542B%u6570%u636E%u5E93%u540D%u79F0%u548C%u96C6%u5408%u540D%u79F0%29%uFF0C%u7136%u540E%u5728%u6839%u636Ens%u548C%u6570%u636E%u5E93%u8DEF%u5F84%u6765%u83B7%u53D6Database%u5BF9%u8C61%uFF0C%u4E00%u4E2ADatabase%u5BF9%u8C61%u4EE3%u8868%u4E00%u4E2A%u6570%u636E%u5E93%28%u8FD9%u90E8%u5206%u5305%u542B%u6570%u636E%u5E93%u6570%u636E%u52A0%u8F7D%uFF0C%u6682%u65F6%u4E0D%u5206%u6790%29%uFF0C%u5982%u679C%u83B7%u53D6%u5230db%u5BF9%u8C61%uFF0C%u5219%u8BBE%u7F6E%u4E0A%u4E0B%u6587%u4FE1%u606F%u3002%0A%0A%u5982%u679C%u6CA1%u6709%u83B7%u53D6%u5230db%u5BF9%u8C61%uFF0C%u5219%u4F1A%u8FDB%u5165%u5230%u4E0B%u9762%3A%0A%0A%20%20%20%20lk.reset%28%20new%20Lock%3A%3ADBRead%28ns%29%20%29%3B%0A%20%20%20%20c.reset%28new%20Context%28ns%2C%20path%29%29%3B%0AContext%u63D0%u4F9B%u4E86%u591A%u4E2A%u6784%u9020%u51FD%u6570%uFF0C%u8FD9%u4E2A%u6784%u9020%u51FD%u6570%u4E2D%u4F1A%u53BB%u521B%u5EFAdb%u5BF9%u8C61%uFF0C%u5E76%u52A0%u8F7D%u6570%u636E%u3002%u9501%u4F4F%u6570%u636E%u5E93%u4E4B%u540E%u5C06%u8FDB%u5165%u6838%u5FC3%u67E5%u8BE2%u90E8%u5206%u3002%0A%0A%20%20%20%20%20//%20Parse%20the%20qm%20into%20a%20CanonicalQuery.%0A%20%20%20%20%20%20%20%20CanonicalQuery*%20cq%3B%0A%20%20%20%20%20%20%20%20Status%20canonStatus%20%3D%20CanonicalQuery%3A%3Acanonicalize%28q%2C%20%26cq%29%3B%0A%20%u9996%u5148%u4F1A%u89E3%u6790%u67E5%u8BE2%u6D88%u606F%u4E3A%u6807%u51C6%u5316%u7684%u67E5%u8BE2%u5BF9%u8C61%uFF0C%u4E3B%u8981%u662F%u5C06BSON%u7ED3%u6784%u6570%u636E%u8F6C%u6362%u4E3AMatchExpression%u65B9%u4FBF%u4F7F%u7528%u3002%0A%20%u4E4B%u540E%u4F1A%u83B7%u53D6%u4E00%u4E2ARunner%u5BF9%u8C61%u6765%u6267%u884C%u67E5%u8BE2%3A%0A%20%0A%0A%09%20%20%20%20Runner*%20rawRunner%20%3D%20NULL%3B%0A%0A%20%20%20%20%20%20%20%20//%20We%20use%20this%20a%20lot%20below.%0A%20%20%20%20%20%20%20%20const%20LiteParsedQuery%26%20pq%20%3D%20cq-%3EgetParsed%28%29%3B%0A%0A%20%20%20%20%20%20%20%20//%20We%27ll%20now%20try%20to%20get%20the%20query%20runner%20that%20will%20execute%20this%20query%20for%20us.%20There%0A%20%20%20%20%20%20%20%20//%20are%20a%20few%20cases%20in%20which%20we%20know%20upfront%20which%20runner%20we%20should%20get%20and%2C%20therefore%2C%0A%20%20%20%20%20%20%20%20//%20we%20shortcut%20the%20selection%20process%20here.%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20%28a%29%20If%20the%20query%20is%20over%20a%20collection%20that%20doesn%27t%20exist%2C%20we%20get%20a%20special%20runner%0A%20%20%20%20%20%20%20%20//%20that%27s%20is%20so%20%28a%20runner%29%20which%20doesn%27t%20return%20results%2C%20the%20EOFRunner.%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20%28b%29%20if%20the%20query%20is%20a%20replication%27s%20initial%20sync%20one%2C%20we%20get%20a%20SingleSolutinRunner%0A%20%20%20%20%20%20%20%20//%20that%20uses%20a%20specifically%20designed%20stage%20that%20skips%20extents%20faster%20%28see%20details%20in%0A%20%20%20%20%20%20%20%20//%20exec/oplogstart.h%29%0A%20%20%20%20%20%20%20%20//%0A%20%20%20%20%20%20%20%20//%20Otherwise%20we%20go%20through%20the%20selection%20of%20which%20runner%20is%20most%20suited%20to%20the%0A%20%20%20%20%20%20%20%20//%20query%20+%20run-time%20context%20at%20hand.%0A%20%20%20%20%20%20%20%20Status%20status%20%3D%20Status%3A%3AOK%28%29%3B%0A%20%20%20%20%20%20%20%20if%20%28collection%20%3D%3D%20NULL%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20rawRunner%20%3D%20new%20EOFRunner%28cq%2C%20cq-%3Ens%28%29%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20if%20%28pq.hasOption%28QueryOption_OplogReplay%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20status%20%3D%20getOplogStartHack%28collection%2C%20cq%2C%20%26rawRunner%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Takes%20ownership%20of%20cq.%0A%20%20%20%20%20%20%20%20%20%20%20%20size_t%20options%20%3D%20QueryPlannerParams%3A%3ADEFAULT%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28shardingState.needCollectionMetadata%28pq.ns%28%29%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20options%20%7C%3D%20QueryPlannerParams%3A%3AINCLUDE_SHARD_FILTER%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20status%20%3D%20getRunner%28cq%2C%20%26rawRunner%2C%20options%29%3B%0A%20%20%20%20%20%20%20%20%7D%0A%u4E0A%u9762%u4EE3%u7801%u8C03%u7528getRunner%u51FD%u6570%u6765%u8FD4%u56DE%u4E00%u4E2ARunner%u5BF9%u8C61%uFF0C%u8BE5Runner%u5BF9%u8C61%u4F1A%u5BF9%u96C6%u5408%u8FDB%u884C%u904D%u5386%uFF0C%u7136%u540E%u627E%u5230%u7B26%u5408%u67E5%u8BE2%u6761%u4EF6%u7684%u7ED3%u679C%u5E76%u8FD4%u56DE%u3002%0A%0A%21%5BAlt%20text%5D%28./%u672A%u547D%u540D.jpg%29%0A%0A%u4E00%u4E2ARunner%u5C31%u4EE3%u8868%u4E00%u79CD%u6570%u636E%u67E5%u8BE2%u65B9%u5F0F%uFF0Cmongo%u4F1A%u6839%u636E%u4E4B%u524D%u7684%u67E5%u8BE2BSON%u89E3%u6790%u7ED3%u679C%u6765%u5224%u65AD%u5E94%u8BE5%u4F7F%u7528%u54EA%u4E00%u79CDRunner%u6765%u6267%u884C%u67E5%u8BE2%uFF0C%u6709%u70B9%u7C7B%u4F3C%u7B56%u7565%u6A21%u5F0F%u3002%0AIDHackRunner%20%uFF1A%20%u5F53%u524D%u96C6%u5408%u662F%u4EE5%u201C_id%u201D%u4F5C%u4E3A%u7D22%u5F15%u6216%u8005%u67E5%u8BE2%u6761%u4EF6%u4E2D%u5305%u542B%22_id%22%u65F6%u5C31%u4F7F%u7528%u6B64%u6765%u67E5%u8BE2%u3002%0ACachedPlanRunner%uFF1A%u5982%u679C%u4E4B%u524D%u5DF2%u7ECF%u6709%u7F13%u5B58plan%uFF0C%u5219%u4F7F%u7528%u6B64%u6765%u67E5%u8BE2%u3002%0AMultiPlanRunner%uFF1A%u4F7F%u7528QueryPlanner%u6765plan%20%u67E5%u8BE2%u6761%u4EF6%uFF0C%u5982%u679C%u7ED3%u679C%u4E3A%u591A%u4E2AQuerySolution%uFF0C%u5219%u4F7F%u7528%u6B64%u6765%u6267%u884C%u67E5%u8BE2%u3002%0ASingleSolutionRunner%uFF1A%u548Cmulti%u76F8%u5BF9%u5E94%uFF0C%u5BF9%u5E94%u4E00%u4E9B%u7B80%u5355%u7684%u67E5%u8BE2%u5219%u4F7F%u7528%u6B64%u6765%u6267%u884C%u3002%0ASubPlanRunner%uFF1A%u6CA1%u641E%u660E%u767D...%0A%0A%u4E0A%u9762%u8FD9%u4E9BRunner%u90FD%u6BD4%u8F83%u590D%u6742%uFF0C%u8BE6%u7EC6%u5206%u6790%u7684%u8BDD%u6BCF%u4E00%u4E2A%u90FD%u80FD%u9700%u8981%u8017%u8D39%u5F88%u591A%u65F6%u95F4%uFF0C%u5176%u4E2D%u5305%u542B%u4E86%u5BF9%u96C6%u5408%u7684%u626B%u63CF%u7B97%u6CD5%uFF0C%u5BF9%u67E5%u8BE2%u7684%u5206%u6BB5%u5904%u7406%u7B49%u7B49%uFF0C%u6574%u4E2Amongod%u7684%u6838%u5FC3%u67E5%u8BE2%u7B97%u6CD5%u90FD%u5C01%u88C5%u5728%u8FD9%u91CC%u9762%uFF0C%u6682%u65F6%u5C31%u4E0D%u6DF1%u5165%u7814%u7A76%u4E86%u3002%0A%0A%20%20%20%20%20%20%20%20//%20Run%20the%20query.%0A%20%20%20%20%20%20%20%20//%20bb%20is%20used%20to%20hold%20query%20results%0A%20%20%20%20%20%20%20%20//%20this%20buffer%20should%20contain%20either%20requested%20documents%20per%20query%20or%0A%20%20%20%20%20%20%20%20//%20explain%20information%2C%20but%20not%20both%0A%20%20%20%20%20%20%20%20BufBuilder%20bb%2832768%29%3B%0A%20%20%20%20%20%20%20%20bb.skip%28sizeof%28QueryResult%29%29%3B%0A%0A%09%20%20%20%20%20%20...%0A%0A%20%20%20%20%20%20%20%20while%20%28Runner%3A%3ARUNNER_ADVANCED%20%3D%3D%20%28state%20%3D%20runner-%3EgetNext%28%26obj%2C%20NULL%29%29%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Add%20result%20to%20output%20buffer.%20This%20is%20unnecessary%20if%20explain%20info%20is%20requested%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%28%21isExplain%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bb.appendBuf%28%28void*%29obj.objdata%28%29%2C%20obj.objsize%28%29%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Count%20the%20result.%0A%20%20%20%20%20%20%20%20%20%20%20%20++numResults%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%7D%0A%u83B7%u53D6Runner%u5BF9%u8C61%u540E%u5F53%u7136%u662F%u4F7F%u7528%u8BE5%u5BF9%u8C61%u6765%u83B7%u53D6%u67E5%u8BE2%u7ED3%u679C%uFF0CRunner%u63D0%u4F9B%u4E00%u4E2AgetNext%u51FD%u6570%u6765%u83B7%u53D6%u4E0B%u4E00%u4E2A%u7ED3%u679C%uFF0C%u4E4B%u540E%u7684%u5C31%u662F%u5C06%u67E5%u8BE2%u7ED3%u679C%u653E%u5230result%u4E2D%uFF0C%u7136%u540E%u8FD4%u56DE%u7ED9%u5BA2%u6237%u7AEF%u3002%0A%0A%u81F3%u6B64%uFF0C%u6574%u4E2A%u6570%u636E%u67E5%u8BE2%u7684%u8F6E%u5ED3%u5DF2%u7ECF%u51FA%u6765%u4E86%uFF0C%u5176%u4E2D%u6570%u636E%u52A0%u8F7D%u548C%u67E5%u8BE2%u7B97%u6CD5%u90E8%u5206%u6211%u90FD%u5F88%u53EA%u662F%u63D0%u4E86%u4E00%u4E0B%u7136%u540E%u7565%u8FC7%uFF0C%u4E3B%u8981%u662F%u6C34%u5E73%u6709%u9650%uFF0C%u5F88%u591A%u4E1C%u897F%u6211%u81EA%u5DF1%u8FD8%u6CA1%u5F04%u660E%u767D%uFF0C%u5199%u51FA%u6765%u4E5F%u90FD%u662F%u9519%u7684%uFF0CMongoDB%u7684%u6BCF%u4E00%u4E2A%u7248%u672C%u4EE3%u7801%u6539%u52A8%u90FD%u5F88%u5927%uFF0C%u53C2%u8003%u4E86%u5F88%u591A%u524D%u8F88%u5BF9%u5176%u4ED6%u7248%u672C%u7684%u5206%u6790%uFF0C%u771F%u662F%u5F88%u4F69%u670D%u4ED6%u4EEC%uFF0C%u5F88%u591A%u4E1C%u897F%u90FD%u5206%u6790%u5F88%u900F%u5F7B%uFF0C%u4F46%u662F%u5BF9%u7167%u6765%u770B%u8FD9%u4E2A%u7248%u672C%u7684%u6E90%u7801%u8FD8%u662F%u6709%u5F88%u591A%u8FF7%u60D1%u7684%u5730%u65B9%uFF0C%u6240%u4EE5%u6570%u636E%u52A0%u8F7D%u548C%u67E5%u8BE2%u7B97%u6CD5%u4E24%u4E2A%u90E8%u5206%u4E4B%u7814%u7A76%u660E%u767D%u4E4B%u540E%u518D%u5355%u72EC%u5F00%u7BC7%u5427%u3002%0A
原文地址:https://www.cnblogs.com/chunxi/p/4390251.html