(-)
mongdb启动代码流程
-------db.cpp-----
main
--mongoDbMain
----initAndListen
------_initAndListen
---------Listen
------------createServer(options, new MyMessageHandler() );
------------startReplication
其中 MyMessageHandler 类就是用来处理 客户端操作的
主要函数如下
virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
//log()<<"-----liguoqing MyMessageHandler->process----"<<this<<"-----"<<getpid()<<endl;
while ( true ) {
if ( inShutdown() ) {
log() << "got request after shutdown()" << endl;
break;
}
lastError.startRequest( m , le );
//log()<<"-------liguoqing---process"<<endl;
DbResponse dbresponse;
try {
assembleResponse( m, dbresponse, port->remote() ); 处理请求参数
}
catch ( const ClockSkewException & ) {
log() << "ClockSkewException - shutting down" << endl;
exitCleanly( EXIT_CLOCK_SKEW );
}
if ( dbresponse.response ) {
port->reply(m, *dbresponse.response, dbresponse.responseTo);
if( dbresponse.exhaustNS.size() > 0 ) {
MsgData *header = dbresponse.response->header();
QueryResult *qr = (QueryResult *) header;
long long cursorid = qr->cursorId;
if( cursorid ) {
verify( dbresponse.exhaustNS.size() && dbresponse.exhaustNS[0] );
string ns = dbresponse.exhaustNS; // before reset() free's it...
m.reset();
BufBuilder b(512);
b.appendNum((int) 0 /*size set later in appendData()*/);
b.appendNum(header->id);
b.appendNum(header->responseTo);
b.appendNum((int) dbGetMore);
b.appendNum((int) 0);
b.appendStr(ns);
b.appendNum((int) 0); // ntoreturn
b.appendNum(cursorid);
m.appendData(b.buf(), b.len());
b.decouple();
DEV log() << "exhaust=true sending more" << endl;
beNice();
continue; // this goes back to top loop
}
}
}
//log()<<"-----liguoqing MyMessageHandler->process----break"<<endl;
break;
}
}
virtual void disconnected( AbstractMessagingPort* p ) {
Client * c = currentClient.get();
if( c ) c->shutdown();
globalScriptEngine->threadDone();
}
};
这里只关心 assembleResponse( m, dbresponse, port->remote() ); 函数的处理
else {
else if ( !nsString.isValid() ) {
// Only killCursors doesn't care about namespaces
uassert( 16257, str::stream() << "Invalid ns [" << ns << "]", false );
}
else if ( op == dbInsert ) {
receivedInsert(m, currentOp); 处理数据插入
}
else if ( op == dbUpdate ) {
receivedUpdate(m, currentOp); 处理数据更新
}
else if ( op == dbDelete ) {
receivedDelete(m, currentOp); 处理数据删除
}
这里只关心 receivedInsert(m, currentOp); 函数处理流程
void receivedInsert(Message& m, CurOp& op) {
bool isIndexWrite = NamespaceString(ns).coll == "system.indexes";-----------------------------创建索引,后续我们在分析索引
// Auth checking for index writes happens further down in this function.
if (!isIndexWrite) {
Status status = cc().getAuthorizationManager()->checkAuthForInsert(ns);
uassert(16544, status.reason(), status.isOK());
}
while (d.moreJSObjs()){
BSONObj obj = d.nextJsObj();
multi.push_back(obj);
if (isIndexWrite) {
string indexNS = obj.getStringField("ns");
uassert(16548,
mongoutils::str::stream() << "not authorized to create index on "
<< indexNS,
cc().getAuthorizationManager()->checkAuthorization(
indexNS, ActionType::ensureIndex));
}
}
while ( true ) {
try {
Lock::DBWrite lk(ns);
// CONCURRENCY TODO: is being read locked in big log sufficient here?
// writelock is used to synchronize stepdowns w/ writes
uassert( 10058 , "not master", isMasterNs(ns) );
if ( handlePossibleShardedMessage( m , 0 ) )
return;
Client::Context ctx(ns);
log()<<"------liguoqing---receivedInsert multi="<<multi.size()<<endl;
if (multi.size() > 1) {
const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError;
insertMulti(keepGoing, ns, multi, op);--------------------------------------------------------------批量插入数据,也是在循环中调用单条插入
} else {
checkAndInsert(ns, multi[0]);---------------------------------------------------------------------单条数据插入
globalOpCounters.incInsertInWriteLock(1);
op.debug().ninserted = 1;
}
return;
}
catch ( PageFaultException& e ) {
e.touch();
}
void checkAndInsert(const char *ns, /*modifies*/BSONObj& js) {
uassert( 10059 , "object to insert too large", js.objsize() <= BSONObjMaxUserSize);------------------------
{
BSONObjIterator i( js );
while ( i.more() ) {
BSONElement e = i.next();
// check no $ modifiers. note we only check top level.
// (scanning deep would be quite expensive)
uassert( 13511, "document to insert can't have $ fields", e.fieldName()[0] != '$' );
// check no regexp for _id (SERVER-9502)
if (str::equals(e.fieldName(), "_id")) {
uassert(16824, "can't use a regex for _id", e.type() != RegEx);
}
}
}
theDataFileMgr.insertWithObjMod(ns,
// May be modified in the call to add an _id field.
js,
// Only permit interrupting an (index build) insert if the
// insert comes from a socket client request rather than a
// parent operation using the client interface. The parent
// operation might not support interrupts.
cc().curop()->parent() == NULL,
false);
sleep(1);
logOp("i", ns, js);
}
这里看insertWithObjMod 函数的处理流程
/** @param o the object to insert. can be modified to add _id and thus be an in/out param
*/
DiskLoc DataFileMgr::insertWithObjMod(const char* ns, BSONObj& o, bool mayInterrupt, bool god) {
bool addedID = false;
DiskLoc loc = insert( ns, o.objdata(), o.objsize(), mayInterrupt, god, true, &addedID );
if( addedID && !loc.isNull() )
o = BSONObj::make( loc.rec() );
return loc;
}
DiskLoc DataFileMgr::insert(const char* ns,
const void* obuf,
int32_t len,
bool mayInterrupt,
bool god,
bool mayAddIndex,
bool* addedID) {
bool addIndex = wouldAddIndex && mayAddIndex; ---------------------这部分是添加索引相关,下期介绍,如 db.coll.ensureIndex({x:1})
NamespaceDetails *d = nsdetails(ns);
if ( d == 0 ) {
d = insert_newNamespace(ns, len, god);
}
NamespaceDetails *tableToIndex = 0;
string tabletoidxns;
BSONObj fixedIndexObject;
if ( addIndex ) {
verify( obuf );
BSONObj io((const char *) obuf);
if( !prepareToBuildIndex(io,
mayInterrupt,
god,
tabletoidxns,
tableToIndex,
fixedIndexObject) ) {
// prepare creates _id itself, or this indicates to fail the build silently (such
// as if index already exists)
return DiskLoc();
}
if ( ! fixedIndexObject.isEmpty() ) {
obuf = fixedIndexObject.objdata();
len = fixedIndexObject.objsize();
}
}
if( !god ) {
/* Check if we have an _id field. If we don't, we'll add it.
Note that btree buckets which we insert aren't BSONObj's, but in that case god==true 判断是否有 _id 字段,如如果没有就加一个
BSONObj io((const char *) obuf);
BSONElement idField = io.getField( "_id" );
uassert( 10099 , "_id cannot be an array", idField.type() != Array );
// we don't add _id for capped collections in local as they don't have an _id index
if( idField.eoo() &&
!wouldAddIndex &&
nsToDatabase( ns ) != "local" &&
d->haveIdIndex() ) {
if( addedID )
*addedID = true;
idToInsert.init();-------------------------------------- 生成_id 的结构体
len += idToInsert.size();
}
// If the collection is capped, check if the new object will violate a unique index
// constraint before allocating space. 处理唯一索引冲突
if (d->nIndexes &&
d->isCapped() &&
!god) {
checkNoIndexConflicts( d, BSONObj( reinterpret_cast<const char *>( obuf ) ) );
}
。。。。。。。。。。。。。。
Record *r = loc.rec();
{
verify( r->lengthWithHeaders() >= lenWHdr );
r = (Record*) getDur().writingPtr(r, lenWHdr);
if( idToInsert.needed() ) {
/* a little effort was made here to avoid a double copy when we add an ID */
int originalSize = *((int*) obuf);
((int&)*r->data()) = originalSize + idToInsert.size();
memcpy(r->data()+4, idToInsert.rawdata(), idToInsert.size());----------------------------memcpy函数将_id和数据插入文件中
memcpy(r->data()+4+idToInsert.size(), ((char*)obuf)+4, originalSize-4);
}
else {
if( obuf ) // obuf can be null from internal callers
memcpy(r->data(), obuf, len);
}
}
至此,数据插入流程结束