设为首页 收藏本站
查看: 1172|回复: 0

[经验分享] Mongodb源码分析--Command体系架构

[复制链接]

尚未签到

发表于 2015-7-6 05:17:26 | 显示全部楼层 |阅读模式
Command在Mongodb中是一类特殊操作,它提供了强大的管理及各项操作(比如建库,索引,删除集合等)。可以说通过Command可以完成几乎所有想做的事情。同时Mongodb开发者在Command上又做了非常清晰体系架构和设计,便于管理和高效执行各种类型的Command。
     今天就专门用一篇篇幅来着重介绍一下其Command的体系架构,并用例子来介绍mongod是如何将Command引入其中的。
   
    为了对其中大部分command对一个大致的了解,我们可以用下面指令来显示一个command列表:


    1.mongod --dbpath d:\mongodb\db --port 27017 --rest
    2.在浏览器上输入链接地址:http://localhost:28017/_commands
     这里mongod就会为我们显示command列表,大约有90多个,这是显示截图:
  
    上面90多个类中,按其使用场景可以为分如下几类,分别是:
    dbcommand.cpp:一般数据库指令,如数据库,索引的创建,重建,打开/关闭等
    dbcommands_admin.cpp:管理指令,如CleanCmd,JournalLatencyTestCmd,ValidateCmd,FSyncCommand
    dbcommands_generic.cpp:常用指令,ListCommandsCmd,LogRotateCmd,PingCommand,CmdSet,CmdGet等
    replset_commands.cpp:复制集指令,CmdReplSetTest,CmdReplSetGetStatus,CmdReplSetReconfig等
    security_commands.cpp:安全指令,CmdGetNonce,CmdLogout,CmdAuthenticate  

    commands_admin.cpp:shard管理操作,因其位于mongos项目,这里暂不介绍
    commands_public.cpp:shard公用操作,因其位于mongos项目,这里暂不介绍  
  
  下面是相关类图:

-----------------------------分割线--------------------------------
  


-----------------------------分割线--------------------------------  
  

-----------------------------分割线--------------------------------   
  

-----------------------------分割线--------------------------------   
  
  首先我们看一下在Command的基类,其用于定义子类要实现的方法及属性,自身也实现了一些通用方法,比如htmlHelp(用于以html方法显示该command的帮助信息),构造方法,findCommand(查询命令)等,其声明如下:
   



    //commands.h
    class Command {
    public:
        //执行当前Command时所使用的锁类型
        enum LockType { READ = -1/*读*/ , NONE = 0 /*无锁*/, WRITE = 1 /*写*/};
        const string name;
        /* 运行指定的命令,需要子类实现
           fromRepl - command is being invoked as part of replication syncing.  In this situation you
                      normally do not want to log the command to the local oplog.
           如执行成功返回true,否则为false, errmsg记录错误信息
        */
        virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) = 0;
        /*
           note: logTheTop() MUST be false if READ
           if NONE, can't use Client::Context setup
                    use with caution
         */
        virtual LockType locktype() const = 0;
        /* 是否有管理特权才可运行该命令 has privileges to run this command. */
        virtual bool adminOnly() const {
            return false;
        }
        //html格式的帮助信息
        void htmlHelp(stringstream&) const;
        /* 与adminOnly相似,但更严格: 要么被验证,要么只运行在本地接口(local interface)         
           注:当本属性为true时,adminOnly()也必须为true.
        */
        virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return false; }
        /* 如果replication pair 的slaves可以运行命令的,则返回true
           (the command directly from a client -- if fromRepl, always allowed).
        */
        virtual bool slaveOk() const = 0;
        /* 通过在查询命令中打开 'slaveok'选项,客户端强制在一个slave上运行一个命令时,返回true.
        */
        virtual bool slaveOverrideOk() {
            return false;
        }
        /* Override and return true to if true,log the operation (logOp()) to the replication log.
           (not done if fromRepl of course)
           Note if run() returns false, we do NOT log.
        */
        virtual bool logTheOp() { return false; }
        virtual void help( stringstream& help ) const;
        /* Return true if authentication and security applies to the commands.  Some commands
           (e.g., getnonce, authenticate) can be done by anyone even unauthorized.
        */
        virtual bool requiresAuth() { return true; }
        /** @param webUI:在web上暴露当前command,形如 localhost:28017/
            @param oldName: 旧选项,表示当前command的旧(已弃用)名称
        */
        Command(const char *_name, bool webUI = false, const char *oldName = 0);
        virtual ~Command() {}
    protected:
        BSONObj getQuery( const BSONObj& cmdObj ) {
            if ( cmdObj["query"].type() == Object )
                return cmdObj["query"].embeddedObject();
            if ( cmdObj["q"].type() == Object )
                return cmdObj["q"].embeddedObject();
            return BSONObj();
        }
        static void logIfSlow( const Timer& cmdTimer,  const string& msg);
        //command map,其包含系统实现的所有command对象,以便findCommand查询时使用
        //注意也包含该command的旧名称(构造方法中的oldName参数)所对应的对象,
        static map * _commands;
        //与上面形同,但不含旧名称的command map
        static map * _commandsByBestName;
        //将web类型的command放到该map中
        static map * _webCommands;
    public:
        static const map* commandsByBestName() { return _commandsByBestName; }
        static const map* webCommands() { return _webCommands; }
        /** @return 返回是否找到或已执行command */
        static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder);
        static LockType locktype( const string& name );
        //根据命令名称在集合中找到相应Command对象
        static Command * findCommand( const string& name );
    };  
    Command基类中提供了几个map类型的集合map,用于将系统实现的Command进行收集,以便后面findCommand进行便历查询时使用。如下:
   



    //commands.cpp
    Command* Command::findCommand( const string& name ) {
        //从_commands map中找到指定name的Command对象
        map::iterator i = _commands->find( name );
        if ( i == _commands->end() )//如果已到结尾,表示未找到
            return 0;
        return i->second;//返回Command对象
    }  
    看到上面代码中的_commands大家可能要问,该map是如何初始化并将系统实现的各个Command注册到其中呢?答案就在Command的构造方法中,如下:
  



    //command.cpp
    Command::Command(const char *_name, bool web, const char *oldName) : name(_name) {
        // register ourself.
        //如为空(系统刚启动时)则实例化_commands
        if ( _commands == 0 )
            _commands = new map;
        //如为空(系统刚启动时)则实例化_commandsByBestName
        if( _commandsByBestName == 0 )
            _commandsByBestName = new map;
        Command*& c = (*_commands)[name];//获取指定名称的command对象
        if ( c )//如有,表示之前已注册了该command
            log() nReturned = 1;
                result.setData( qr.release(), true );//设置返回结果
            }
            else {
                uasserted(13530, "bad or malformed command request?");
            }
            return 0;
        }
    .....
    }  
    上面代码对传递来的查询消息QueryMessage(有关消息机制参见我的这篇文章)进行分析之后,如果发现其为command时,执行runCommands方法:




     //query.cpp   
     bool runCommands(const char *ns, BSONObj& jsobj, CurOp& curop, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions) {
        try {
            return _runCommands(ns, jsobj, b, anObjBuilder, fromRepl, queryOptions);
        }
        catch ( AssertionException& e ) {
            e.getInfo().append( anObjBuilder , "assertion" , "assertionCode" );
        }
        curop.debug().str ensureStarted();
        string dbname = nsToDatabase( ns );
        if( logLevel >= 1 )
            log()

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83459-1-1.html 上篇帖子: MongoDB数据访问[C#] 下篇帖子: MongoDB初识
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表