redis的c++客户端cpp_redis代码分析

cpp_redis是一个基于c++11编写的redis客户端,比较简单,也比较强大,支持集群

本篇分析是基于一个简单的set命令来展开的

为了便于调试和查看代码运行轨迹,编译时用如下命令:

cmake -DBUILD_EXAMPLES=true -DLOGGING_ENABLED=true .

这是查看完CMakefile.txt后得出的



cpp_redis使用了tacopie库,这个库的作者和cpp_redis是一个人,类结构层次如下:

tacopie:
    tcp_client {io_service, m_socket, std::queue<read_request> m_read_requests, std::queue<write_request> m_write_requests}
        io_service
        {
            std::unordered_map<fd_t, tracked_socket> m_tracked_sockets,
            std::thread m_poll_worker;
            utils::thread_pool m_callback_workers;
                {
                    std::vector<std::thread> m_workers; 线程
                    std::queue<task_t> m_tasks; 函数
                }
            std::vector<struct pollfd> m_poll_fds_info;
            tacopie::self_pipe m_notifier; pipe;
            std::condition_variable m_wait_for_removal_condvar;
                io_service::wait_for_removal(const tcp_socket& socket)
                循环等待直到socket不在m_tracked_sockets中
                
                tcp_client::disconnect(bool wait_for_removal)如果指定wait_for_removal为true,调用
                    
        }
        m_socket
            tcp_socket {m_fd, m_host, m_port, m_type}


cpp_redis:
    future_client {
        redis_client m_client
        {
            redis_connection
            {
                tacopie::tcp_client m_client;
                
                reply_callback_t m_reply_callback;
                    std::function<void(redis_connection&, reply&)>
                    void redis_client::connection_receive_handler(network::redis_connection&, reply& reply)
                        从redis_client对象的m_callbacks中取出1个
                        如果用户定义了m_before_callback_handler,则执行m_before_callback_handler(reply, callback);
                        callback也作为参数传递给用户的回调函数,用户可选择性调callback
                        否则执行callback(reply);
                        通知等待变量
                    
                disconnection_handler_t m_disconnection_handler;
                    void redis_client::connection_disconnection_handler(network::redis_connection&)
                        清空redis_client对象的m_callbacks队列,并通知等待变量
                        调用用户的回调函数m_disconnection_handler(*this);
                    
                builders::reply_builder m_builder;
                std::string m_buffer;
                std::mutex m_buffer_mutex;
            }
            std::queue<reply_callback_t> m_callbacks;
                std::function<void(reply&)>
            
            //user defined disconnection handler
            disconnection_handler_t m_disconnection_handler;
            //user defined before callback handler
            std::function<void(reply&, reply_callback_t& callback)> m_before_callback_handler;
            
            std::condition_variable m_sync_condvar;用于同步提交redis命令
        }


至此,类型结构描述结束,下面是执行set命令的流程       

        future exec_cmd(std::function<redis_client& (const redis_client::reply_callback_t&)> f) {
            auto prms = std::make_shared<promise>();
            f([prms](reply& reply) {
                prms->set_value(reply);
            }).commit(); f的返回值是redis_client,调用完f函数后,再调用返回的redis_client的commit方法
            调用f的过程,
                [=](const rcb_t& cb) -> rc& { return m_client.setex(key, seconds, value, cb); });
                实际是调用m_client.setex(key, seconds, value, cb);
                    cb是
                        [prms](reply& reply) {
                            prms->set_value(reply);
                        }
                m_client.setex返回redis_client对象,实际就是m_client自己
                    send({"SETEX", key, std::to_string(seconds), value}, reply_callback);
                        m_client.send(redis_cmd);
                            redis_connection::send
                                m_buffer += build_command(redis_cmd);
                                一条redis的命令如下,4个参数:
                                *4\r\n
                                $len(key)\r\n
                                key\r\n
                                ...
                        m_callbacks.push(callback); cb存入队列
                        返回
            f调用完返回redis_client,再调用其commit方法
                redis_client::try_commit
                    redis_connection::commit
                        std::string buffer = std::move(m_buffer);
                        m_client.async_write({std::vector<char>{buffer.begin(), buffer.end()}, nullptr});
                            tcp_client::async_write(const write_request& request)
                                m_io_service->set_wr_callback(m_socket, std::bind(&tcp_client::on_write_available, this, std::placeholders::_1));
                                    设置m_socket的写回调tcp_client::on_write_available
                                    m_notifier.notify();向管道中写入a
                                    
                                    在io_service构造时创建了m_poll_worker线程,函数是io_service::poll
                                    是个循环,每次循环都调用init_poll_fds_info,将m_tracked_sockets和m_fds[0]放入监听集合
                                    m_tracked_sockets中的fd如果设置了对应的回调函数,并且当前没有在执行,则监听对应的事件
                                    m_fds[0]监听读事件
                                    所有这些读事件,都放在m_poll_fds_info集合
                                    
                                    调用::poll(const_cast<struct pollfd*>(m_poll_fds_info.data()), m_poll_fds_info.size(), -1)
                                    如果有事件,则调用process_events(),没有事件则阻塞
                                    
                                    m_fds[0]的读事件直接清空管道(读1024个字符),忽略
                                    如果监听的fd返回写事件,wr_callback存在,当前没有执行,则process_wr_event(poll_result, socket);
                                    封装一个task_t给线程池m_callback_workers执行,task_t先执行用户的回调函数wr_callback(fd);
                                    如果该fd标记了marked_for_untrack,则从m_tracked_sockets去除,通知m_wait_for_removal_condvar.notify_all
                                    
                                    因为task_t是异步执行的,在process_events函数里也执行了一遍marked_for_untrack,并且没有先查找
                                    是因为process_events先拥有了m_tracked_sockets_mtx,而process_wr_event在删之前也要获得这个锁.
                                    如果process_events当时没有删,之后又设置了,则process_wr_event可以删
                                    
                                    process_rd_event类似于process_wr_event。
                                    
                                    m_notifier.notify();继续驱动事件处理(为什么写在循环内,这样写了多个a)
                                    
                                    
                                    tcp_client::on_write_available
                                        auto callback = process_write(result);
                                            从m_write_requests中取出一个request,m_socket.send(request.buffer, request.buffer.size());
                                            auto callback       = request.async_write_callback;
                                            如果m_write_requests没有要发送的请求,则m_io_service->set_wr_callback(m_socket, nullptr);
                                            即不监听写事件了
                                            
                                            没有发送成功,则disconnect();
                                                m_io_service->untrack(m_socket);
                                                    it->second.marked_for_untrack = true;这里设置了untrack,异步任务执行完可以删
                                                if (wait_for_removal) { m_io_service->wait_for_removal(m_socket); } 等待fd从map中删除
                                                    默认是false
                                                m_socket.close();
                                        callback(result);//这里是nullptr
                                            
                                            
                                m_write_requests.push(request);
                                    request存入m_write_requests队列
                
            在connect调用时注册了tcp_client_receive_handler,即
            m_client.async_read({__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)});
                m_io_service->set_rd_callback(m_socket, std::bind(&tcp_client::on_read_available, this, std::placeholders::_1));
                m_read_requests.push(request);
                也就是响应回来,调用tcp_client::on_read_available
                    auto callback = process_read(result);
                        从m_read_requests取出一个request对象
                        result.buffer  = m_socket.recv(request.size);
                        result.success = true;
                        如果请求队列现在空了,m_io_service->set_rd_callback(m_socket, nullptr);
                    调用用户定义的callback(result);即redis_connection::tcp_client_receive_handler
                        将request读出来的字节流作为输入给m_builder,生成多个reply。
                        如果构建reply失败,调用m_disconnection_handler,即redis_client::connection_disconnection_handler
                            clear_callbacks();清空m_callbacks队列
                            call_disconnection_handler()
                                m_disconnection_handler(*this);即用户定义的断开连接回调
                        对每一个reply,调用m_reply_callback(*this, reply);即redis_client::connection_receive_handler
                            上面已经分析过,从callback队列中得到一个回调函数,即f的参数对应的lamada函数
                            [prms](reply& reply) {
                                prms->set_value(reply);
                            }
                        
                        m_client.async_read({__CPP_REDIS_READ_SIZE, std::bind(&redis_connection::tcp_client_receive_handler, this, std::placeholders::_1)});
                        继续注册读事件
                        
            return prms->get_future();
        }
    }
    
connect流程就是设值,连接。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值