MongoDB Source Analysis (19) initialization of MONGOs and connection pool allocation collection

Source: Internet
Author: User
Tags auth bind bool connection pooling min mongodb socket

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




















Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.