• mongo源码学习(三)请求接收传输层


    在上一篇博客中(mongo源码学习(二)db.cpp之mongoDbMain方法分析),我们把db.cpp中的mongoDbMain的执行过程分析了一下,最后会调用initAndListen(serverGlobalParams.port)方法来监听端口,默认的是27017了。程序执行到这块就断开了,追踪不下去了。在另一个地方肯定有accept方法来接收客户端的请求。然后找了半天发现了文件夹transportlayer,发现了里面有相关的代码。

    transport_layer.h

    // mongo的命名空间
    namespace mongo {
    
    class OperationContext;
    
    // transport的命名空间, 我是cpp小白, 命名空间还可以嵌套, TODO:namespace学习一下
    namespace transport {
    
    // 连接的SSL模型, TODO:SSL可以了解一下哦
    enum ConnectSSLMode { kGlobalSSLMode, kEnableSSL, kDisableSSL };
    
    // 这个应该声明的意思, TODO:C++声明类
    class Reactor;
    
    // using还可以这么用, shared_ptr是啥, 可以了解一下
    // 妈的, 写不下去了, 就我这这样的还来看mongo的C++源码
    using ReactorHandle = std::shared_ptr<Reactor>;
    
    /**
     * The TransportLayer moves Messages between transport::Endpoints and the database.
     * This class owns an Acceptor that generates new endpoints from which it can
     * source Messages.
     *
     * The TransportLayer creates Session objects and maps them internally to
     * endpoints. New Sessions are passed to the database (via a ServiceEntryPoint)
     * to be run. The database must then call additional methods on the TransportLayer
     * to manage the Session in a get-Message, handle-Message, return-Message cycle.
     * It must do this on its own thread(s).
     *
     * References to the TransportLayer should be stored on service context objects.
     */
    /**
     * TransportLayer在transport::Endpoints和database(也就是mongo了)之间传递消息(message)。
     * 这个类有一个Acceptor, 这个Acceptor可以从原始的message中生成一个新的endpoints。
     *
     * TransportLay创建新的Session对象,并且在内部将它们映射到endpoints。新的Session通过一个ServiceEntryPoint
     * 传递到database来运行的。database后面必须调用TransportLay的其他方法来管理get-Message,
     * handle-Message和return-Message周期中的Session。而且必须在它自己的线程中做这些事。
     */
    class TransportLayer {
        // 这是个什么鬼
        MONGO_DISALLOW_COPYING(TransportLayer);
    
    public:
    
        // 声明各种状态
        static const Status SessionUnknownStatus;
        static const Status ShutdownStatus;
        static const Status TicketSessionUnknownStatus;
        static const Status TicketSessionClosedStatus;
        // 把Session对象设为友元
        friend class Session;
        // virtual, TODO:虚方法了解一下
        virtual ~TransportLayer() = default;
        // 连接
        virtual StatusWith<SessionHandle> connect(HostAndPort peer,
                                                  ConnectSSLMode sslMode,
                                                  Milliseconds timeout) = 0;
        // 异步连接
        virtual Future<SessionHandle> asyncConnect(HostAndPort peer,
                                                   ConnectSSLMode sslMode,
                                                   const ReactorHandle& reactor,
                                                   Milliseconds timeout) = 0;
    
        /**
         * Start the TransportLayer. After this point, the TransportLayer will begin accepting active
         * sessions from new transport::Endpoints.
         */
        /**
         * 启动TransportLayer。在这之后,TransportLayer将开始从新的transport::Endpoints接收活跃的session。
         */
        virtual Status start() = 0;
    
        /**
         * Shut the TransportLayer down. After this point, the TransportLayer will
         * end all active sessions and won't accept new transport::Endpoints. Any
         * future calls to wait() or asyncWait() will fail. This method is synchronous and
         * will not return until all sessions have ended and any network connections have been
         * closed.
         */
        /**
         * 关闭TransportLay。在这之后,TransportLayer将终止所有活跃的sessions并且不再接收新的EndPoints。
         * 任何将来对wait()和asyncWait()的调用都会失败。这个方法是同步的,并且直到所有的sessions都结束了
         * 之后并且任何网络连接都关闭了才会返回。
         */
        virtual void shutdown() = 0;
    
        /**
         * Optional method for subclasses to setup their state before being ready to accept
         * connections.
         */
        /**
         * 这个是可选的方法,子类可以用这个方法在准备接收连接的时候去设置它们的状态。
         */
        virtual Status setup() = 0;
    
        enum WhichReactor { kIngress, kEgress, kNewReactor };
        virtual ReactorHandle getReactor(WhichReactor which) = 0;
    
        virtual BatonHandle makeBaton(OperationContext* opCtx) {
            return nullptr;
        }
    
    protected:
        TransportLayer() = default;
    };
    }  // namespace transport
    }  // namespace mongo

    这里看着有点绕,主要的几个角色有:

    TransportLayer:有Acceptor接收请求,产生新的EndPoints,创建Session,并将Session在内部映射到EndPoints上;同时TransportLayer也在EndPoints和database之间传递消息。

    Session:get-Message,handle-Message和return-Message,但是这些需要TransportLayer来管理。

    EndPoints:抽象出来的端的概念。

    Acceptor:接收请求的。

    database:我们的mongo后台

    TransportLayer类图

    这里画了一下TransportLayer的类图:

    image

    我倒是在浏览代码的时候对TransportLayer所起的作用有了一定的认识,但是还不是很深入。对TransportLayer角色的定位不清楚,就像类图中所说的,尼玛,它怎么会有connect方法呢?我现在非常想找的是服务器端接收客户端的accept方法在哪儿?

    经过了一番摸索,终于找到了accept方法了,原来就在TransportLayerASIO中。根据这几天的学习,大概总结出了下面的这个模型:

    image

    纯属本人自己看源码总结的,不一定保证正确。其实到这里来我们压根还没深入到数据库中,最多只是到了数据库的门口,也就是ServiceEntryPoint,不过也算开了个头。在上图中我画了一条水平的虚线,我想表达的是,在虚线上方的东西基本上给哪个C/S架构的系统都是可以用的,在根本模型还是最简单的Socket的通信,不过加了很多东西。

    虽然这些代码对我这个小白来说也也挺用处的,但是看mongo的源码个人觉得重要的还是:存储引擎,事务,锁,集群这些东西更好玩。功力较浅加上C++不怎么熟,所有看起来还是有点吃力,喜欢的朋友可以关注下,我就更有动力了。有了面向对象的思想看C++如果不执着于细节,看懂的话可以达到5,6成。有些时候只用看一些函数调用,但是有些时候需要深入到函数里面看一下,这个也没有啥经验,反正就是做实验一样去试吧。

    在看TransportLayer的代码的时候,看到了一个叫状态机的玩意,注释解释的意思是,mongod是一个无状态的服务,但是客户端是有状态的,为了进行这种有状态/无状态的转换,就用到了这个向量机。感觉挺叼的,无状态的好处很多,但是自己实际工作中用的还比较少。

    另外一个就是用到了命令设计模式,也是值得我去看的。

    我有一个大胆而不成熟的想法,看mongo的C++源码,然后用golang去重写一遍,带垃圾回收的除了java都不用,好疯狂

  • 相关阅读:
    java web环境搭建
    java动手动脑异常处理
    java动手动脑多态
    python全栈开发day67--字段类型、字段属性、ORM回顾
    python全栈开发day66-视图系统、路由系统
    python全栈开发day65-templates:tags、母版和继承、组件、静态文件相关、simple_tag和inclusion_tag
    python全栈开发day64-模板-变量和(.)的使用,filters和自定义filter
    Django Models的数据类型汇总
    nginx反向代理uwsgi django服务器搭建总结
    Centos更新yum源
  • 原文地址:https://www.cnblogs.com/tuhooo/p/9849654.html
Copyright © 2020-2023  润新知