MONGOs is an automatic slicing component provided by MongoDB, in which almost all requests are forwarded through MONGOs to Mongod in MongoDB systems that provide fragmentation, and then mongos to be aggregated and finally returned to the client. To analyze and analyze the initialization of MONGOs , for the back through the MONGOs query, delete, modify, add records MapReduce aggregate and MONGOs automatic fragmentation and load balancing to prepare. Here's a look at the code, its entry is main in Mongo\s\server.cpp, Remove the processing command line Parameters section, directly from its formal start function Runmongosserver start.
static bool Runmongosserver (bool Doupgrade) {Pool.addhook (new Shardingconnectionhook (false));//mongos use connection pooling to manage connections.
This sets the callback function for the connection pool and, for Shardingconnectionhook (false), verifies the user name and password pool.setname ("MONGOs connectionpool") only when a new connection is created; Shardconnectionpool.addhook (New Shardingconnectionhook (True)),//for which the Shardingconnectionhook argument is true, depending on the type of connection, For master (single server) set (Replset mode), you need to send the command setshardversion to the connection default, passing your own ServerID (an OID type, automatically generated), which will be used later in this ServerID,
Forward the MONGOs error forwarding data back to the mongs, so that it is correctly forwarded to the corresponding Mongod, this section is specifically used in an article discussed.
Shardconnectionpool.setname ("MONGOs shardconnection connectionpool"); MONGOs shouldn ' t lazily kill cursors, otherwise we can end up with extras from migration Dbclientconnection::setlaz
Ykillcursor (FALSE);
Replicasetmonitor::setconfigchangehook (Boost::bind (&configserver::replicasetchange, &ConfigServer, _1));
if (! Configserver.init (Configdbs)) {//configserver initialization, set Configserver address.
return false; if (! Configserver.ok (tRue)) {//Configserver to ensure that the connection Configserver return false; {class Checkconfigservers:public Task::task {virtual string name () const {return "checkconf Igservers ";
virtual void DoWork () {Configserver.ok (true);}
}; Task::repeat (new checkconfigservers, 60*1000)//Here check once every 60 seconds Configserver can connect} int configerror = CONFIGSERVER.CHEC Kconfigversion (Doupgrade)//update config version, can only upgrade from version 2 to 3 version, the action is simply to back up the original data if (Configerror) {//Then read its data, according to the latest 3 version of the data to write to the Coll
In Ection, no further analysis of return false;
Configserver.reloadsettings ()//Read the settings in the Configserver to ensure that some of the data is indexed.
Init ();
#if!defined (_win32) Cmdline::launchok (); #endif if (!nohttpinterface) Boost::thread web (Boost::bind (&webserverthread, New noadminaccess ()/* tak
ES ownership *));
Messageserver::options opts;
Opts.port = Cmdline.port;
Opts.iplist = cmdline.bind_ip;
Start (opts)//starts the service. Listen () would return to when exIt code closes its socket.
Dbexit (Exit_net_error);
return true;
}
Runmongoserver->configserver::init
BOOL Configserver::init (vector<string> confighosts) {string hn = GetHostName ();
Set<string> hosts;
For (size_t i=0 i<confighosts.size (); i++) {string host = Confighosts[i];
Hosts.insert (GetHost (host, false))//server address, without port confighosts[i] = GetHost (host, true);//server address with Port
For (Set<string>::iterator I=hosts.begin (); I!=hosts.end (); i++) {string host = *i;
bool OK = false;
for (int x=10; x>0; x--) {//the server is resolved through Getnameinfo, if (! Hostbyname (Host.c_str ()). Empty ()) {
OK = true;
Break
} sleepsecs (10);
if (! OK) return false;
} _config = confighosts;//save configuration string fullstring; Joinstringdelim (confighosts, &fullstring, ', ')//Connect all server addresses _primary.setaddress (COnnectionstring (fullstring, Connectionstring::sync))//10gen recommend that you do not use only one configserver in a production environment, where multiple servers work in SYNC mode,
Is that all request processing is sent to multiple servers set up here.
return true;
}
Runmongoserver->configserver::ok
BOOL Configserver::ok (bool checkconsistency) {
if (! _primary.ok ())//init when the address return false is set
;
if (checkconsistency) {
string errmsg;
if (! checkconfigserversconsistent (errmsg)) {//detect whether each configserver is reachable, and whether the data in Configserver is consistent return
false;
}
}
return true;
}
Runmongoserver->configserver::ok->checkconfigserversconsistent
BOOL Configserver::checkconfigserversconsistent (string& errmsg, int tries) Const {unsigned firstgood =
0;
int up = 0;
vector<bsonobj> Res;
for (unsigned i=0; i<_config.size (); i++) {bsonobj x; try {scoped_ptr<scopeddbconnection> conn (//pool Connection pool is assigned a connection, timeout is set to 30s SCOPEDDB
Connection::getinternalscopeddbconnection (_config[i], 30.0));
Check auth conn->get ()->update ("Config.foo.bar", Bsonobj (), Bson ("x" << 1));
Conn->get ()->simplecommand ("admin", &x, "GetLastError"); if (x["Err"].type () = = String && x["Err"].
String () = = "Unauthorized") {errmsg = "not authorized, did for you to start with--keyfile?";
return false; } if (! Conn->get ()->simplecommand ("config", &x, "Dbhash"))/to ConfiG database executes Dbhash command to get its x = Bsonobj ();
else {x = x.getowned ();
if (up = = 0) Firstgood = i;
up++;
} conn->done ();
} res.push_back (x);
} if (_config.size () = = 1) return true;
if (up = = 0) {errmsg = "no config servers reachable";
return false;
} if (up = = 1) return true; Bsonobj base = res[firstgood];//the hash in all Collections.chunks collection from the first accessible configserver to the last one is consistent for (Unsig Ned I=firstgood+1; I<res.size ();
i++) {//inconsistency is configserver in an inconsistent state.
if (Res[i].isempty ()) continue;
String C1 = base.getfielddotted ("Collections.chunks");
string C2 = res[i].getfielddotted ("Collections.chunks"); string D1 = base.getfielddotted ("Collections. Databases ");
String d2 = res[i].getfielddotted ("collections.databases");
if (c1 = = C2 && D1 = = D2) continue;
StringStream SS;
SS << "config Servers" << _config[firstgood] << "and" << _config[i] << "differ";
Log (ll_warning) << ss.str ();
if (tries <= 1) {errmsg = Ss.str ();
return false;
Return Checkconfigserversconsistent (ErrMsg, tries-1);
return true;
}
Return to the Runmongosserver function to continue parsing the reloadsettings.
void Configserver::reloadsettings () {set<string> got; Scoped_ptr<scopeddbconnection> Conn (Scopeddbconnection::getinternalscopeddbconnection (_primary.get
ConnString (), 30.0));
try {//Find the data in the settings in the Configserver.
auto_ptr<dbclientcursor> C = conn->get ()->query (Shardns::settings, Bsonobj ());
while (C->more ()) {//Get chunksize value, default to 64M bsonobj o = C->next ();
String name = o["_id"].valuestrsafe ();
Got.insert (name);
if (name = = "Chunksize") {int csize = o["value"].numberint (); Validate chunksize before proceeding if (CSize = 0) {//setting is not Modified
Mark as such got.erase (name);
else {chunk::maxchunksize = csize * 1024 * 1024;
} } if (! Got.count ("chunksize")) {//default one chunk size is 64M conn->get (
)->insert (Shardns::settings, Bson ("_id" << "chunksize" <<
"Value" << (chunk::maxchunksize/(1024 * 1024)));
//indexes, indexed, will be used later.
Conn->get ()->ensureindex (Shardns::chunk, Bson ("ns" << 1 << "min" << 1), true); Conn->get ()->ensureindex (Shardns::chunk, Bson ("ns" << 1 << "Shar"
D "<< 1 <<" min "<< 1), true);
Conn->get ()->ensureindex (Shardns::chunk, Bson ("ns" << 1 << "Lastmod" << 1), true);
Conn->get ()->ensureindex (Shardns::shard, Bson ("host" << 1), true);
Conn->done ();
}
}
Keep Runmongosserver->init.
void Init () {
serverid.init ();//serverid generation
setupsigtrapforgdb ();
Setupcoresignals ();
Setupsignals (false);
Logstream::get (). Addglobaltee (New Ramlog ("global"));
Finally to the start function. runmongoserver->start
void start (const messageserver::options& opts) {
balancer.go ()/Balance thread, the balance of the data in Shard is the thread responsible, It policy the data in a certain amount of servers to handle the balance
cursorcache.starttimeoutthread ();//cursorcache cache cursor, this opens a thread, No request will be cursor cleared within 10 minutes.
Periodictask::therunner->go ();//As the provider of the service, provides a thread for task execution.
Shardedmessagehandler Handler;//mongos socket The actual processing end, analyzed in the Mongod analysis of this structure, createserver generation of a handler process,
Messageserver * Server = Createserver (opts, &handler); This no longer analyzes, will direct channel shardedmessagehandler the message processing part.
Server->setastimetracker ();
Server->run ();
}
Continue to parse MONGOs functions for Socket request Processing: Shardedmessagehandler::p rocess.
virtual void process (message& m, abstractmessagingport* p, LastError * le) {
Request R (M, p);
Lasterror.startrequest (M, le);
try {
r.init ();
R.process ();
}
Here MONGOs initialization is done, and finally take a look at a typical process of requesting a connection from a connection pool. The above article has seen that its typical code is as follows:
Scoped_ptr<scopeddbconnection> Conn (
scopeddbconnection::getinternalscopeddbconnection) (_ Primary.getconnstring (), 30.0));
Enter Getinternalscopedbconnection
scopeddbconnection* scopeddbconnection::getinternalscopeddbconnection (const string& host,double socketTimeout) {return
getscopeddbconnection (host, sockettimeout);
}
scopeddbconnection* scopeddbconnection::getscopeddbconnection (const string& host,double socketTimeout) {
return new Scopeddbconnection (host, sockettimeout);
}
Explicit scopeddbconnection (const string& Host, double sockettimeout = 0): _host (Host), _conn (Pool.get (host, Sockett imeout)), _sockettimeout (sockettimeout) {//Note the _conn here, which pulls a connection from the global connection pool.
_setsockettimeout ();
}
Continue pool.get below.
dbclientbase* dbconnectionpool::get (const string& host, double sockettimeout) {
dbclientbase * c = _get (host, so Ckettimeout);//Find the connection pool if a connection already exists
if (c) {//exists to take out, and then call the hook function set here for connection pooling.
Onhandedout (c);
return c;
}
string errmsg;
ConnectionString cs = ConnectionString::p arse (host, errmsg);//Create a new connection
C = Cs.connect (errmsg, sockettimeout);
return _finishcreate (Host, Sockettimeout, c);
}
dbclientbase* dbconnectionpool::_get (const string& ident, double sockettimeout) {
scoped_lock L (_mutex);
poolforhost& p = _pools[poolkey (ident,sockettimeout)];
Return P.get (this, sockettimeout);
Keep Poolforhost::get.
Dbclientbase * Poolforhost::get (Dbconnectionpool * pool, double sockettimeout) {
time_t now = time (0);
while (! _pool.empty ()) {
Storedconnection sc = _pool.top ();
_pool.pop ();
if (! Sc.ok (now)) {//30 minutes Connection not requested closes
Pool->ondestroy (sc.conn);//callback hook function before shutdown.
Delete Sc.conn;
Continue;
}
return sc.conn;
}
return NULL;
}
Continue dbconnectionpool::get->connectionstring::p arse
ConnectionString ConnectionString::p arse (const string& host, string& errmsg) {str
Ing::size_type i = host.find ('/'); if (i!= string::npos && i!= 0) {//replset mode//Replica set return ConnectionString (set
, Host.substr (i + 1), host.substr (0, i));
int numcommas = Str::count (host, ', ');
if (numcommas = 0)//Only one machine, Master mode return ConnectionString (Hostandport (host));
if (Numcommas = = 1) return ConnectionString (PAIR, host);
if (Numcommas = = 2) return ConnectionString (SYNC, host);
ErrMsg = (string) "Invalid hostname [" + Host + "]"; return ConnectionString (); INVALID}
ConnectionString (connectiontype type, const string& s, const string& setname = "") {
_type = type;
_setname = SetName;
_fillservers (s);//parsing s, dividing it into one server address
_finishinit ();
Keep Dbconnectionpool::get->connectionstring::connect.
dbclientbase* Connectionstring::connect (string& errmsg, double sockettimeout) const {switch (_type) {
Establish different connections based on different types.
Case MASTER: {dbclientconnection * c = new dbclientconnection (true);
C->setsotimeout (sockettimeout);
return C; Case Pair:case Set: {dbclientreplicaset * set = new Dbclientreplicaset (_setname, _server
s, sockettimeout);
return set;
Case SYNC: {//TODO, don ' t copy listDbconnectionpool::get->dbconnectionpool::_finishcreate
dbclientbase* dbconnectionpool::_finishcreate (const string& host, double sockettimeout, dbclientbase* conn) {
{
scoped_lock L (_mutex);
poolforhost& p = _pools[poolkey (host,sockettimeout)];
P.createdone (conn);//The number of connections created plus one, the connection has not been saved here and will be saved to Poolforhost when the connection Conn released later.
} When the called Connection is released, it is saved to the poolforhost here.
OnCreate (conn);//connection created hook function for pool shardingconnectionhook.
Onhandedout (conn);
return conn;
}
Keep looking at the hook function here.
void Shardingconnectionhook::oncreate (DBCLIENTBASE * conn) {if (!noauth) {//authentication process.
string err;
BOOL result = Conn->auth ("local", internalsecurity.user,internalsecurity.pwd,err,false); if (conn->type () = = Connectionstring::sync) {//connections to the Config servers should always have
Full access.
Conn->setauthenticationtable (Authenticationtable::getinternalsecurityauthenticationtable ()); }//ISVERSIONABLECB is true if the connection is master or set mode _shardedconnections && VersionManager . ISVERSIONABLECB (conn)) {//Here for Shardconnectionpool,_shardedconnections is true//We must initialize Sharding
On ' All connections ' so ' we get ' exceptions if Sharding is enabled on//the collection.
Bsonobj result;
bool OK = VERSIONMANAGER.INITSHARDVERSIONCB (conn, result);/send Setshardversion command, pass to local ServerID Assert that we actually successfully setup sharding}}
Continue to see the release of the connection. Scopeddbconnection::d One
void Done () {
_conn->clearauthenticationtable ();
Pool.release (_host, _conn);
_conn = 0;
}
void Dbconnectionpool::release (const string& host, Dbclientbase *c) {
if (c->isfailed ()) {
OnDestroy (c) ;
Delete C;
return;
}
Scoped_lock L (_mutex);
_pools[poolkey (Host,c->getsotimeout ())].done (this,c);//Add an idle connection to the pool.
}
The connection is recycled here and the contents of this article are complete.
Original link: MongoDB source analysis (19) MONGOs initialization and connection pool allocation Recycle Author: yhjj0108, Yang Hao