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

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

MONGOs is the automatic Shard component provided by MongoDB, in the MongoDB system that provides the Shard function, almost all of the requests will be forwarded to the Mongod through MONGOs, and then the MONGOs is aggregated and returned to the client. The initial analysis MONGOs initialization , for later through MONGOs query, delete, modify, add to record MapReduce aggregate and MONGOs automatic shard and load balance to prepare. Here's the code, whose entry is the main in Mongo\s\server.cpp, Remove the part of the command line argument which is processed directly from its formal start function runmongosserver.

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 only when a new connection is created, validates the user name and password pool.setname ("MONGOs connectionpool"); Shardconnectionpool.addhook (New Shardingconnectionhook (true));//For this shardingconnectionhook parameter 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 by default, pass your own ServerID (an OID type, auto-generated), and the ServerID will be used later,
    Forward the data that MONGOs incorrectly forwards back to the mongs, so that it is correctly forwarded to the appropriate Mongod, which is later specifically addressed in an article.
    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 is initialized, the address of the Configserver is set.
  
    return false; if (! Configserver.ok (tRue)) {//Connect Configserver, make sure to connect 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);//Check once every 60 seconds if configserver can be connected} int configerror = CONFIGSERVER.CHEC Kconfigversion (Doupgrade);//update config version, only from version 2 to version 3, 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 written to the Coll
    Ection, no more in-depth 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 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--) {//through Getnameinfo resolution server, if (! Hostbyname ()). 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 your production environment, where multiple servers work in SYNC mode,
        Is that all request processing is sent to more than one server set here.
    return true;
 }
Runmongoserver->configserver::ok

    BOOL Configserver::ok (bool checkconsistency) {
        if (! _primary.ok ())//init when the address return is already set to
            false;
        if (checkconsistency) {
            string errmsg;
            if (! checkconfigserversconsistent (errmsg)) {//detects if each configserver is reachable and 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, time-out is set to 30s SCOPEDDB
                Connection::getinternalscopeddbconnection (_config[i], 30.0));
                Check auth conn->get ()->update ("Config.foo.bar", Bsonobj (), BSON ("x" << 1));//Checks for permissions
                Conn->get ()->simplecommand ("admin", &x, "GetLastError"); if (x["Err"].type () = = String && x["Err"].
                    String () = = "Unauthorized") {errmsg = "not authorized, do you start with--keyfile?";
                return false; } if (! Conn->get ()->simplecommand ("config", &x, "Dbhash")//To ConfiThe G database executes the 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];//matches the hash in all of its Collections.chunks collection from the first configserver to the last (Unsig Ned I=firstgood+1; I<res.size ();
            i++) {//inconsistency 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;
 }
Go back to the Runmongosserver function to continue analyzing reloadsettings.

    void Configserver::reloadsettings () {set<string> got; Scoped_ptr<scopeddbconnection> Conn (Scopeddbconnection::getinternalscopeddbconnection (_primary.get
        ConnString (), 30.0));
            try {//Find data in Settings in Configserver.
            auto_ptr<dbclientcursor> C = conn->get ()->query (Shardns::settings, Bsonobj ());
                while (C->more ()) {//Gets chunksize value, default is 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, build the index, 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, In accordance with a certain policy, the data in the various servers to deal with the balance between the
        cursorcache.starttimeoutthread ();//cursorcache cache cursor, open a thread here, There is no request to clear the cursor within 10 minutes.
        Periodictask::therunner->go ();//As the provider of the service, provide the thread that the task executes.
        Shardedmessagehandler Handler;//mongos socket Actual processing end, in the analysis of mongod analysis of this structure, createserver generation of a handler process,
        Messageserver * Server = Createserver (opts, &handler); Here no longer analyzes the message Processing section that will be directed to the channel Shardedmessagehandler.
        Server->setastimetracker ();
        Server->run ();
    }
The following continues the analysis of 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 work is done, and finally a typical process of requesting a connection from a connection pool. The above article has been seen, 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 is a connection taken 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 out if the connection pool is already connected
        if (c) {///exists then remove, then call the hook function of the connection pool setting here.
            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 without the requested connection close
                Pool->ondestroy (sc.conn);//callback hook function before closing.
                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);//parse S, divide 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);//Create a connection number plus one, where the connection has not been saved and will be saved to Poolforhost when the connection Conn released later.
        When the called connection is freed, it is saved to the poolforhost here.
        OnCreate (conn);//The hook function created by the connection, for pool is shardingconnectionhook.
        Onhandedout (conn);
        return conn;
    }
Continue to see 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 has
                Full access.
            Conn->setauthenticationtable (Authenticationtable::getinternalsecurityauthenticationtable ()); }//ISVERSIONABLECB true if the connection is in master or set mode (_shardedconnections && VersionManager . ISVERSIONABLECB (conn)) {//Here is true for shardconnectionpool,_shardedconnections//We must initialize Sharding
            On all connections, so, we get exceptions if sharding are 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.
    }

Here the connection is recycled, the content of this article is complete.


SOURCE Link: MongoDB Source code Analysis (19) MONGOs initialization and connection pool allocation recycling 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.