当前位置: 首页 > article >正文

【RabbitMQ 项目】服务端:数据管理模块之绑定管理

文章目录

  • 一.编写思路
  • 二.代码实践

一.编写思路

  1. 定义绑定信息类
    1. 交换机名称
    2. 队列名称
    3. 绑定关键字:交换机的路由交换算法中会用到
      没有是否持久化的标志,因为绑定是否持久化取决于交换机和队列是否持久化,只有它们都持久化时绑定才需要持久化。绑定就好像一根绳子,两端连接着交换机和队列,当一方不存在,它就没有存在的必要了
  2. 定义绑定持久化类
    1. 构造函数:如果数据库文件不存在则创建,打开数据库,创建 binding_table
    2. 插入交换机和队列的绑定
    3. 移除交换机和队列的绑定
    4. 移除与指定交换机相关的所有绑定
    5. 移除与指定队列相关的所有绑定
    6. 从数据库中恢复绑定到内存
    7. 删除绑定数据库表(仅调试)
  3. 定义绑定管理类
    1. 构造函数:从数据库中恢复绑定
    2. 绑定交换机和队列
    3. 解绑交换机和队列
    4. 解绑与指定交换机相关的绑定:移除交换机时要用到
    5. 解绑与指定队列相关的绑定:移除队列时要用到
    6. 获取交换机相关的所有绑定信息:交换路由时要用到
    7. 销毁所有绑定(仅调试)

二.代码实践

Binding.hpp

#pragma once
#include "../common/Util.hpp"
#include <memory>
#include <unordered_map>
#include <mutex>
/***************
 * 定义绑定信息类
 * **************/
namespace ns_data
{
    class Binding;
    using BindingPtr = std::shared_ptr<Binding>;
    using BindingMap = std::unordered_map<std::string, std::unordered_map<std::string, BindingPtr>>;
    struct Binding
    {
        std::string _exchangeName;
        std::string _msgQueueName;
        std::string _bindingKey;

        Binding(const std::string &exchangeName, const std::string &msgQueueName, const std::string &bindingKey)
            : _exchangeName(exchangeName),
              _msgQueueName(msgQueueName),
              _bindingKey(bindingKey)
        {
        }
    };

    class BindingMapper
    {
    private:
        ns_util::Sqlite3Util _sqlite;

    public:
        BindingMapper(const std::string &dbName)
            : _sqlite(dbName)
        {
            if (!ns_util::FileUtil::createFile(dbName))
            {
                LOG(FATAL) << "create database " << dbName << " fail" << endl;
                exit(1);
            }
            if (!_sqlite.open())
            {
                LOG(FATAL) << "open database " << dbName << " fail" << endl;
                exit(1);
            }
            createTable();
        }

        /****************
         * 插入绑定
         * *************/
        bool insertBinding(BindingPtr bindingPtr)
        {
            char insertSql[1024];
            sprintf(insertSql, "insert into binding_table values('%s', '%s', '%s');", bindingPtr->_exchangeName.c_str(),
                    bindingPtr->_msgQueueName.c_str(), bindingPtr->_bindingKey.c_str());
            if (!_sqlite.exec(insertSql, nullptr, nullptr))
            {
                LOG(WARNING) << "insert Binding fail: " << bindingPtr->_exchangeName << "->" << bindingPtr->_msgQueueName;
                return false;
            }
            return true;
        }

        /***********
         * 移除交换机和队列的绑定
         * ****************/
        void removeBinding(const std::string &exchangeName, const std::string &msgQueueName)
        {
            char deleteSql[1024];
            sprintf(deleteSql, "delete from binding_table where exchange_name='%s' and msg_queue_name='%s';",
                    exchangeName.c_str(), msgQueueName.c_str());
            if (!_sqlite.exec(deleteSql, nullptr, nullptr))
            {
                LOG(WARNING) << "remove Binding fail: " << exchangeName << "->" << msgQueueName << endl;
            }
        }

        /****************
         * 移除指定交换机相关的所有绑定
         * ************/
        void removeExchangeBindings(const std::string &exchangeName)
        {
            char deleteSql[1024];
            sprintf(deleteSql, "delete from binding_table where exchange_name='%s';", exchangeName.c_str());
            if (!_sqlite.exec(deleteSql, nullptr, nullptr))
            {
                LOG(WARNING) << "remove exchange Bindings fail, exchange: " << exchangeName << endl;
            }
        }

        /****************
         * 移除指定队列相关的所有的绑定
         * ************/
        void removeMsgQueueBindings(const std::string &msgQueueName)
        {
            char deleteSql[1024];
            sprintf(deleteSql, "delete from binding_table where msg_queue_name='%s';", msgQueueName.c_str());
            if (!_sqlite.exec(deleteSql, nullptr, nullptr))
            {
                LOG(WARNING) << "remove msg_queue Bindings fail, exchange: " << msgQueueName << endl;
            }
        }

        /******************
         * 恢复数据库中绑定到内存
         * BindingMap是一个二维数组,通过交换机名称和队列名称即可得到Binding的智能指针
         * **************/
        void recoverBindings(BindingMap* mapPtr)
        {
            const std::string selectSql = "select * from binding_table;";
            if (!_sqlite.exec(selectSql.c_str(), selectCallback, mapPtr))
            {
                LOG(FATAL) << "recover Bindings from binding_table fail" << endl;
                exit(1);
            }
        }

        /*********
         * 删除绑定数据库表(仅调试)
         * *************/
        void removeTable()
        {
            const std::string dropSql = "drop table if exists binding_table;";
            if (_sqlite.exec(dropSql.c_str(), nullptr, nullptr))
            {
                LOG(FATAL) << "drop binding_table fail" << endl;
            }
        }

    private:
        void createTable()
        {
            const std::string createSql = "create table if not exists binding_table(\
                exchange_name varchar(32),\
                msg_queue_name varchar(32),\
                binding_key varchar(32),\
                primary key(exchange_name, msg_queue_name)\
            );";

            if (!_sqlite.exec(createSql.c_str(), nullptr, nullptr))
            {
                LOG(FATAL) << "create table binding_table fail" << endl;
                exit(1);
            }
        }

        static int selectCallback(void* arg, int colNum, char** line, char** fields)
        {
            auto mapPtr = static_cast<BindingMap*>(arg);
            const std::string exchangeName = line[0];
            const std::string msgQueueName = line[1];
            const std::string bindingKey = line[2];

            auto bindingPtr = std::make_shared<Binding>(exchangeName, msgQueueName, bindingKey);
            (*mapPtr)[exchangeName][msgQueueName] = bindingPtr;
            return 0;
        }
    };

    class BindingManager
    {
    private:
        BindingMapper _mapper;
        BindingMap _bindings;
        std::mutex _mtx;
    public:
        BindingManager(const std::string& dbName)
            :_mapper(dbName)
        {
            _mapper.recoverBindings(&_bindings);
        }

        /**********
         * 绑定交换机和队列
         * 说明:让上层判断交换机和队列的持久性来告诉我Binding是否需要持久化,如果自己判断耦合度太高了
         * ***********/
        bool bind(const std::string &ename, const std::string &qname, const std::string& bindingKey, bool durable)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            if (_bindings.count(ename) && _bindings[ename].count(qname))
            {
                return true;
            }
            auto bindingPtr = std::make_shared<Binding>(ename, qname, bindingKey);
            _bindings[ename][qname] = bindingPtr;

            if (durable)
            {
                return _mapper.insertBinding(bindingPtr);
            }
            return true;
        }

        /**********
         * 解绑交换机和队列
         * 说明:让上层判断交换机和队列的持久性来告诉我Binding是否需要持久化,如果自己判断耦合度太高了
         * 如果用户不说明,默认它是持久化的,执行一遍delete语句也不会出错
         * ***********/
        void unbind(const std::string &ename, const std::string &qname, bool durable = true)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            if (_bindings.count(ename) == 0 || _bindings[ename].count(qname) == 0)
            {
                return;
            }
            if (durable)
            {
                _mapper.removeBinding(ename, qname);
            }
            _bindings[ename].erase(qname);
        }

        /**************
         * 解绑与指定交换机相关的绑定:删除交换机后要调用该接口
         * ******************/
        void removeExchangeBindings(const std::string &ename)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            if (_bindings.count(ename) == 0)
            {
                return;
            }
            _mapper.removeExchangeBindings(ename);
            _bindings.erase(ename);
        }

        /**************
         * 解绑与指定交换机相关的绑定:删除队列后要调用该接口
         * ******************/
        void removeMsqQueueBindings(const std::string &qname)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            _mapper.removeMsgQueueBindings(qname);
            for (auto it = _bindings.begin(); it != _bindings.end(); it++)
            {
                it->second.erase(qname);
            }
        }

        /***************
         * 获取指定的绑定
         * ***********/
        BindingPtr getBinding(const std::string& ename, const std::string& qname)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            if (_bindings.count(ename) == 0 || _bindings[ename].count(qname) == 0)
            {
                return nullptr;
            }
            return _bindings[ename][qname];
        }

        /**************
         * 获取和指定交换机相关的绑定:路由交换时要用到该接口
         * ***************/
        bool getExchangeBindings(const std::string& ename, std::unordered_map<std::string, BindingPtr>* mapPtr)
        {
            std::unique_lock<std::mutex> lck(_mtx);
            if (_bindings.count(ename) == 0)
            {
                *mapPtr = std::unordered_map<std::string, BindingPtr>();
                return false;
            }
            *mapPtr = _bindings[ename];
            return true;
        }

        /**************
         * 清空绑定(仅调试)
         * ************/
        void clearBindings()
        {
            std::unique_lock<std::mutex> lck(_mtx);
            _bindings.clear();
            _mapper.removeTable();
        }
        
    };
}

http://www.kler.cn/a/305635.html

相关文章:

  • C++ QT 工具日志异步分批保存
  • 【深度学习】LSTM、BiLSTM详解
  • 16008.行为树(五)-自定义数据指针在黑板中的传递
  • 论文分享:DiskANN查询算法
  • YOLOV8应用|排球垫球计数|附带全部数据集与源码(见文末百度云盘链接)
  • 如何管理好自己的LabVIEW项目
  • PostgreSQL 与 MySQL:如何为你的项目选择合适的数据库?
  • 闲鱼 sign 阿里228滑块 分析
  • Spring事务传播行为详解
  • 【JavaScript】LeetCode:36-40
  • 使用Python实现深度学习模型:智能饮食建议与营养分析
  • OSS对象资源管理
  • React函数组件传参
  • 大数据-127 - Flink State 04篇 状态原理和原理剖析:状态存储 Part2
  • 汽车以太网100BASE-T1 和 1000BASE-T1特性
  • QXml 使用方法
  • 关于linux里的df命令以及inode、数据块-stat链接数以及关于awk文本处理命令中内置函数sub、gsub、sprintf
  • Excel 国产化替换新方案
  • cc2530按键中断实现控制LED
  • 【MySQL】MySQL索引与事务的透析——(超详解)
  • 情感识别系统源码分享
  • 【hot100-java】【搜索二维矩阵 II】
  • 如何应对突发的技术故障和危机?
  • Redis集群_主从复制
  • 每日学习一个数据结构-倒排表
  • Lua热更