本来简单讲讲mongos对于查询 添加 的流程,修改和删除的处理流程简单其也与添加差不多不再分析,对于添加 修改和删除,mongos都只是将其发往正确的mongod服务器让其处理,对于查询稍微麻烦点,因为查询多个mongod服务器的结果回来时汇总需要mongos自身完成其排序.下面来看具体代码吧,在mongos的初始化部分我们已经知道向mongos发送的请求,其处理函数是Request::process函数,下面来看看这个函数.
void Request::process( int attempt ) {
init();//初始化,加载要操作的数据库的DBConfig,对于sharded collection还要加载其chunkmanager
int op = _m.operation();
if ( op == dbKillCursors ) {
cursorCache.gotKillCursors( _m );
return;
}
int msgId = (int)(_m.header()->id);
Timer t;
Strategy * s = SHARDED;
_counter = &opsNonSharded;
_d.markSet();
bool iscmd = false;
if ( op == dbQuery ) {
iscmd = isCommand();
s->queryOp( *this );
}
else if ( op == dbGetMore ) {
checkAuth( Auth::READ ); // this is important so someone can't steal a cursor
s->getMore( *this );
}
else {
checkAuth( Auth::WRITE );
s->writeOp( op, *this );
}
globalOpCounters.gotOp( op , iscmd );
_counter->gotOp( op , iscmd );
}
首先来看查询dbQuery部分.这里查询调用的是ShardStrategy::queryOp
virtual void queryOp( Request& r ) {
// TODO: These probably should just be handled here.
if ( r.isCommand() ) {//对于mongos的命令请求,不再分析
SINGLE->queryOp( r );
return;
}
QueryMessage q( r.d() );
r.checkAuth( Auth::READ );
QuerySpec qSpec( (string)q.ns, q.query, q.fields, q.ntoskip, q.ntoreturn, q.queryOptions );
if ( _isSystemIndexes( q.ns ) && q.query["ns"].type() == String && r.getConfig()->isSharded( q.query["ns"].String() ) ) {
// if you are querying on system.indexes, we need to make sure we go to a shard that actually has chunks
// this is not a perfect solution (what if you just look at all indexes)
// but better than doing nothing
ShardPtr myShard;//查询的是xx.system.indexes这个collection,这个collection保存了所有索引信息.
ChunkManagerPtr cm;//每一个ns得到的要么是chunkManager(对应ns分片了),要么是shard(对应的ns未分片)
r.getConfig()->getChunkManagerOrPrimary( q.query["ns"].String(), cm, myShard );
if ( cm ) {
set shards;
cm->getAllShards( shards );
verify( shards.size() > 0 );
myShard.reset( new Shard( *shards.begin() ) );
}
doQuery( r, *myShard );//将查询发往myShard
return;
}//并行cursor的初始化
ParallelSortClusteredCursor * cursor = new ParallelSortClusteredCursor( qSpec, CommandInfo() );
// TODO: Move out to Request itself, not strategy based
{
long long start_millis = 0;
if ( qSpec.isExplain() ) start_millis = curTimeMillis64();
cursor->init();//这里内部多cursor的建立,每一个shard一个cursor
shardedCursorTypes.hit( cursor->type() );
if ( qSpec.isExplain() ) {
// fetch elapsed time for the query
long long elapsed_millis = curTimeMillis64() - start_millis;
BSONObjBuilder explain_builder;
cursor->explain( explain_builder );
explain_builder.appendNumber( "millis", elapsed_millis );
BSONObj b = explain_builder.obj();
replyToQuery( 0 , r.p() , r.m() , b );
delete( cursor );
return;
}
}
if( cursor->isSharded() ){
ShardedClientCursorPtr cc (new ShardedClientCursor( q , cursor ));
BufBuilder buffer( ShardedClientCursor::INIT_REPLY_BUFFER_SIZE );
int docCount = 0;
const int startFrom = cc->getTotalSent();//从cursor中读取数据填充buffer
bool hasMore = cc->sendNextBatch( r, q.ntoreturn, buffer, docCount );
if ( hasMore ) {//有更多数据则先将其保存起来,下次再用.一直不操作600s后将被清除
cursorCache.store( cc );
}
replyToQuery( 0, r.p(), r.m(), buffer.buf(), buffer.len(), docCount,
startFrom, hasMore ? cc->getId() : 0 );
}
else{//该collection未分片,则其在在一台服务器上.
// Remote cursors are stored remotely, we shouldn't need this around.
// TODO: we should probably just make cursor an auto_ptr
scoped_ptr cursorDeleter( cursor );
// TODO: Better merge this logic. We potentially can now use the same cursor logic for everything.
ShardPtr primary = cursor->getPrimary();//得到其所在的服务器
DBClientCursorPtr shar