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:\n" << 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

时间: 2024-10-15 12:17:29

MongoDB源码分析——mongod数据查询操作的相关文章

转:Mongodb源码分析之Replication模式

原文出处:http://www.cnblogs.com/daizhj/archive/2011/06/13/mongodb_sourcecode_rep mongodb中提供了复制(Replication)机制,通过该机制可以帮助我们很容易实现读写分离方案,并支持灾难恢复(服务器断电)等意外情况下的数据安全. 在老版本(1.6)中,Mongo提供了两种方式的复制:master-slave及replica pair模式(注:mongodb最新支持的replset复制集方式可看成是pair的升级版,

Solr4.8.0源码分析(5)之查询流程分析总述

Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilter的dofilter开始.dofilter包含了对http的各个请求的操作.Solr的查询方式有很多,比如q,fq等,本章只关注select和q.页面下发的查询请求如下:http://localhost:8080/solr/test/select?q=code%3A%E8%BE%BD*+AND+l

jQuery源码分析系列(38) : 队列操作

Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Queue队列 队列是一种特殊的线性表,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).队列的特点是先进先出(FIFO-first in first out),即最先插入的元素最先被删除. 为什么要引入队列? 我们知道代码的执行流有异步与同步之分,例如 var a

Hadoop HDFS源码分析 关于数据块的类

Hadoop HDFS源码分析 关于数据块的类 1.BlocksMap 官方代码中的注释为: /** * This class maintains the map from a block to its metadata. * block's metadata currently includes blockCollection it belongs to and * the datanodes that store the block. */ BlocksMap数据块映射,管理名字节点上的数据

jQuery 源码分析(十三) 数据操作模块 DOM属性 详解

jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DOM属性的静态方法接口如下: prop(elem, name, value)    ;设置或读取DOM属性,有两种用法,如下 ·$.prop(elem,name,value)      ;传入第三个参数表示设置elem元素的name属性值为value ·$.prop(elem,name,)      

springMVC源码分析--HttpMessageConverter数据转化(一)

之前的博客我们已经介绍了很多springMVC相关的模块,接下来我们介绍一下springMVC在获取参数和返回结果值方面的处理.虽然在之前的博客老田已经分别介绍了参数处理器和返回值处理器: (1)springMVC参数值处理器 springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一) (2)springMVC返回值处理器 springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一) 但对参数和返回值

MongoDB源码分析——mongo与JavaScript交互

mongo与JavaScript交互 源码版本为MongoDB 2.6分支     之前已经说过mongo是MongoDB提供的一个执行JavaScript脚本的客户端工具,执行js其实就是一个js和c++互相调用的过程,当然,因为mongo采用了Google V8 JS引擎,所以调用的实现的核心都由V8实现了,本篇只是分析了mongo是如何使用V8实现功能,对V8的源码不做分析. 为了了解mongo是如何使用js,我们首先从connect说起: mongo::ScriptEngine::set

HDFS源码分析(三)-----数据块关系基本结构

前言 正如我在前面的文章中曾经写过,在HDFS中存在着两大关系模块,一个是文件与block数据块的关系,简称为第一关系,但是相比于第一个关系清晰的结构关系,HDFS的第二关系就没有这么简单了,第二关系自然是与数据节点相关,就是数据块与数据节点的映射关系,里面的有些过程的确是错综复杂的,这个也很好理解嘛,本身block块就很多,而且还有副本设置,然后一旦集群规模扩大,数据节点的数量也将会变大,如何处理此时的数据块与对应数据节点的映射就必然不是简单的事情了,所以这里有一点是比较特别的,随着系统的运行

CI源码分析(四)—DB查询缓存

(一) 使用 创建缓存文件目录, 保证目录可写 在config/database.php中配置缓存路径 : db['default′]['cachedir′]='path/to/cache/dir′启用||关闭缓存:可以使用代码控制,只对部分代码生效–this->db->cache_on(), this?>db?>cacheoff();也可以通过配置文件配置,对所有代码生效-db['default']['cache_on'] = true; 建议在配置文件中关闭,然后在使用的地方自