exchange.hpp交换机模块

一.Exchange相关类介绍

二.Exchange类的实现

交换机类型

对于 RabbitMQ 来说, 主要⽀持四种交换机类型: 
• Direct 
• Fanout 
• Topic 
• Header 
其中 Header 这种⽅式⽐较复杂, ⽐较少⻅。常⽤的是前三种交换机类型,项⽬中也主要实现这三种 
• Direct: ⽣产者发送消息时, 指定被该交换机绑定的所有队列中满足(RoutingKey==BindingKey)的
• Fanout: ⽣产者发送的消息会被复制到该交换机绑定的所有队列中  
• Topic: 绑定队列到交换机上时, 指定⼀个字符串为 BindingKey。发送消息指定⼀个字符串为 
RoutingKey。当 RoutingKey 和 BindingKey满⾜⼀定的匹配条件的时候, 则把消息投递到指定队列

交换机类型的定义

// 交换机类型
enum ExchangeType
{
    UNKNOWNTYPE = 0;
    DIRECT = 1;
    FANOUT = 2;
    TOPIC = 3;
};

// 消息投递模式(决定是否持久化)
enum DeliverMode
{
    NORMAL = 0;
    UNDURABLE = 1;
    DURABLE = 2;
};

Exchange类的相关接口

主要成员变量

  • _namestd::string 类型,表示交换机的名称。
  • _typemsg::ExchangeType 类型,表示交换机的类型。
  • _durablebool 类型,表示交换机是否持久化。
  • _auto_delbool 类型,表示交换机是否自动删除。
  • _argsgoogle::protobuf::Map<std::string, std::string> 类型,用于存储交换机的其他参数。这个 Map 用于键值对存储交换机的自定义属性。
std::string _name;                                     // 交换机名称
msg::ExchangeType _type;                               // 交换机类型
bool _durable;                                         // 是否持久化
bool _auto_del;                                        // 是否自动删除
google::protobuf::Map<std::string, std::string> _args; // 其它参数

公有成员函数

setArgs 函数
  • 用于从格式化字符串中解析出参数并存储到 _args 成员变量中。格式化字符串的格式是 key=val&key=val...,多个键值对通过 & 符号分隔。
  • 实现思路:首先将字符串按 & 进行分割,然后对于每个键值对,按 = 分割为键和值,并存入 _args 中。如果格式错误(找不到 =),则记录错误日志并终止程序。
void setArgs(const std::string &str_args)
{
    std::vector<std::string> args;
    size_t sz = StrHelper::split(str_args, "&", args);
    for (auto &kv : args)
    {
        size_t pos = kv.find("=");
        if (pos == std::string::npos)
        {
            ELOG("Exchange args format error:%s", kv.c_str());
            assert(0);
        }
        std::string key = kv.substr(0, pos);
        std::string val = kv.substr(pos + 1);
        _args[key] = val;
    }
}
getArgs 函数
  • _args 成员变量中的kv参数转换为格式化字符串,格式同上。它遍历 _args Map,将每个键值对拼接为字符串并以 & 符号分隔。
std::string getArgs()
{
    std::string ret;
    for (auto &kv : _args)
    {
        ret += kv.first + "=" + kv.second + "&";
    }
    return ret;
}

三.ExchangeMapper类的实现

ExchangeMapper 类负责Exchange 对象的属性持久化到数据库中,并提供了对这些数据的插入、删除和查询等操作。它通过 SqliteHelper 类与 SQLite 数据库进行交互,确保 Exchange 对象的信息能够在数据库中保存和恢复

主要成员变量

  • sql_helperSqliteHelper 类型,用于管理与 SQLite 数据库的连接和操作

构造函数

  • ExchangeMapper(const std::string &dbname):构造函数接受一个数据库文件的路径 dbname,并使用 SqliteHelper 进行数据库连接的初始化。如果数据库文件所在路径不存在,则会自动创建。同时,构造函数会调用 createTable 方法创建存储 Exchange 信息的表

公有成员函数

createTable

用于在数据库中创建存储 Exchange 对象信息的表 exchange_table。表中包含以下字段:

args:存储其他参数的字符串。

auto_del:是否自动删除。

durable:是否持久化。

type:交换机类型。

name:交换机名称,作为主键。

void createTable()
{
    std::stringstream sql;
    sql << "create table if not exists exchange_table\
    ('name' varchar(64) primary key,\
    type int,durable int,auto_del int,args varchar(128));";
    if (!sql_helper.exec(sql.str(), nullptr, nullptr))
    {
        ELOG("ExchangeMapper create table error!");
        assert(0);
    }
}
dropTable
  • 用于删除 exchange_table
void dropTable()
{
    std::stringstream sql;
    sql << "drop table if exists exchange_table;";
    if (!sql_helper.exec(sql.str(), nullptr, nullptr))
    {
        ELOG("ExchangeMapper drop table error!");
        assert(0);
    }
}
insert
  • 将一个 Exchange 对象插入到 exchange_table 表中。它将对象的各个成员变量转化为 SQL 语句中的对应字段值,并执行插入操作。
void insert(Exchange::ptr &exchange_ptr)
{
    std::stringstream sql;
    sql << "insert into exchange_table values('" << exchange_ptr->_name << "'," << exchange_ptr->_type << "," << exchange_ptr->_durable << ","
        << exchange_ptr->_auto_del << ",'"
        << exchange_ptr->getArgs() << "');";
    if (!sql_helper.exec(sql.str(), nullptr, nullptr))
    {
        ELOG("ExchangeMapper insert error!");
        assert(0);
    }
}
remove
  • exchange_table 表中删除指定名称的 Exchange 对象
void remove(const std::string &name)
{
    std::stringstream sql;
    sql << "delete from exchange_table where name='" << name << "';";
    if (!sql_helper.exec(sql.str(), nullptr, nullptr))
    {
        ELOG("ExchangeMapper remove error!");
        assert(0);
    }
}
recover
  • exchange_table 表中查询所有的 Exchange 对象,并将它们恢复为 Exchange 对象存储在一个哈希表(exchange_map)中返回。该函数使用一个回调函数 exchangeMapCb 处理查询结果,将每一行记录转化为 Exchange 对象。

using exchange_map = std::unordered_map<std::string, Exchange::ptr>;

exchange_map recover()
{
    exchange_map ret;
    std::stringstream sql;
    sql << "select * from exchange_table;";
    if (!sql_helper.exec(sql.str(), exchangeMapCb, &ret))
    {
        ELOG("ExchangeMapper recover error!");
        assert(0);
    }
    return ret;
}
exchangeMapCb
  • 该静态回调函数在 recover 函数中被调用,用于将数据库查询结果中的每一行转化为一个 Exchange 对象,并将其存储到 exchange_map 中。
static int exchangeMapCb(void *args, int rows, char **ret, char **fields)
{
    Exchange::ptr exchange_ptr = std::make_shared<Exchange>();
    exchange_map *map_ptr = (exchange_map *)args;
    exchange_ptr->_name = ret[0];
    exchange_ptr->_type = (msg::ExchangeType)std::stoi(ret[1]);
    exchange_ptr->_durable = std::stoi(ret[2]);
    exchange_ptr->_auto_del = std::stoi(ret[3]);
    if (ret[4])
    {
        exchange_ptr->setArgs(ret[4]);
    }
    map_ptr->insert(std::make_pair(exchange_ptr->_name, exchange_ptr));
    return 0;
}

四.ExchangeManager类的实现

ExchangeManager 类用于管理系统中的 Exchange 对象,并提供声明、删除、查询、判断存在性以及清理等功能。该类在内部通过一个 ExchangeMapper 实例与数据库交互,以实现 Exchange 对象的持久化和恢复。

主要成员变量

  • _mutexstd::mutex 类型,用于确保多线程环境下对 _exchanges 数据结构的安全访问。
  • _mapperExchangeMapper 类型,用于与数据库进行交互,负责 Exchange 对象的持久化操作。
  • _exchangesexchange_map 类型,用于在内存中存储所有当前管理的 Exchange 对象

构造函数

  • ExchangeManager(const std::string &dbname):构造函数接受一个数据库文件的路径 dbname,通过 ExchangeMapper 从数据库中恢复已存储的 Exchange 对象到内存中_exchanges 哈希表。

成员函数(增删查)

declareExchange 函数

声明一个 Exchange 对象,如果该名称的 Exchange 已存在则直接返回 true。如果不存在,则创建一个新的 Exchange 对象并插入到 _exchanges 中,并在持久化标志 _durabletrue 时,将其插入到数据库中。

bool declareExchange(const std::string &name, msg::ExchangeType type,
                     bool durable,
                     bool auto_del,
                     google::protobuf::Map<std::string, std::string> args)
{
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _exchanges.find(name);
    if (it != _exchanges.end())
    {
        ILOG("ExchangeManager declareExchange:%s already exists!", name.c_str());
        return true;
    }
    Exchange::ptr exchange_ptr = std::make_shared<Exchange>(name, type, durable, auto_del, args);
    _exchanges.insert(std::make_pair(name, exchange_ptr));
    if (exchange_ptr->_durable == true)
        _mapper.insert(exchange_ptr);
    return true;
}
removeExchange 函数
  • 删除一个指定名称的 Exchange 对象。如果该对象存在且是持久化的,则同时从数据库中删除该记录。
bool removeExchange(const std::string &name)
{
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _exchanges.find(name);
    if (it == _exchanges.end())
    {
        ILOG("ExchangeManager removeExchange not found!");
        return true;
    }
    _exchanges.erase(it);
    if (it->second->_durable)
        _mapper.remove(name);
    return true;
}
selectExchange 函数
  • 获取指定名称的 Exchange 对象的智能指针,如果未找到则返回一个空的智能指针
Exchange::ptr selectExchange(const std::string &name)
{
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _exchanges.find(name);
    if (it == _exchanges.end())
        return Exchange::ptr();
    else
        return it->second;
}
exists 函数
bool exists(const std::string &name)
{
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _exchanges.find(name);
    return it != _exchanges.end();
}
clear 函数

清理内存中的 _exchanges 哈希表,并删除数据库中的 exchange_table 表。

void clear()
{
    std::unique_lock<std::mutex> lock(_mutex);
    _exchanges.clear();
    _mapper.dropTable();
}
size 函数
size_t size()
{
    std::unique_lock<std::mutex> lock(_mutex);
    return _exchanges.size();
}

五.exchange.hpp所有代码

#pragma once

#include "../common_mq/helper.hpp"
#include "../common_mq/logger.hpp"
#include "../common_mq/msg.pb.h"
#include <string>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <cassert>
#include <cstring>
#include <google/protobuf/map.h>
namespace mq
{
    struct Exchange
    {
        using ptr = std::shared_ptr<Exchange>;
        Exchange() {}
        Exchange(const std::string &name, msg::ExchangeType type,
                 bool durable,
                 bool auto_del,
                 const google::protobuf::Map<std::string, std::string> &args)
            : _name(name),
              _type(type),
              _durable(durable),
              _auto_del(auto_del),
              _args(args) {}

        // args存储键值对,在存储数据库的时候,会组织一个格式字符串进行存储 key=val & key=val....
        // 内部解析str_args字符串,将内容存储到成员中
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> args;
            size_t sz = StrHelper::split(str_args, "&", args);
            for (auto &kv : args)
            {
                size_t pos = kv.find("=");
                if (pos == std::string::npos)
                {
                    ELOG("Exchange args format error:%s", kv.c_str());
                    assert(0);
                }
                std::string key = kv.substr(0, pos);
                std::string val = kv.substr(pos + 1);
                _args[key] = val;
                // ILOG("Exchange args:%s", kv.c_str());
            }
        }
        std::string getArgs()
        {
            std::string ret;
            for (auto &kv : _args)
            {
                ret += kv.first + "=" + kv.second + "&";
            }

            return ret;
        }

        std::string _name;                                     // 交换机名称
        msg::ExchangeType _type;                               // 交换机类型
        bool _durable;                                         // 是否持久化
        bool _auto_del;                                        // 是否自动删除
        google::protobuf::Map<std::string, std::string> _args; // 其它参数
};

    using exchange_map = std::unordered_map<std::string, Exchange::ptr>;

    // 在数据库中 存储exchange信息
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string &dbname)
            : sql_helper(dbname)
        {
            // 数据库有path即可,open时自动创建文件
            std::string path = FileHelper::getParentDirName(dbname);
            FileHelper::createDir(path);
            if (!sql_helper.open())
            {
                ELOG("ExchangeMapper open error!");
                assert(0);
            }
            // std::cout<<"创建表!!!"<<std::endl;
            createTable();
        }
        ~ExchangeMapper() {}
        // 1.创建/删除Exchange表
        void createTable()
        {
            // std::cout<<"创建表!!!"<<std::endl;
            std::stringstream sql;
            sql << "create table if not exists exchange_table\
            ('name' varchar(64) primary key,\
            type int,durable int,auto_del int,args varchar(128));";
            if (!sql_helper.exec(sql.str(), nullptr, nullptr))
            {
                ELOG("ExchangeMapper create table error!");
                assert(0);
            }
        }
        void dropTable()
        {
            std::stringstream sql;
            sql << "drop table if exists exchange_table;";
            if (!sql_helper.exec(sql.str(), nullptr, nullptr))
            {
                ELOG("ExchangeMapper drop table error!");
                assert(0);
            }
        }
        // 2.插入/删除Exchange
        void insert(Exchange::ptr &exchange_ptr)
        {
            std::stringstream sql;
            sql << "insert into exchange_table values('" << exchange_ptr->_name << "'," << exchange_ptr->_type << "," << exchange_ptr->_durable << ","
                << exchange_ptr->_auto_del << ",'"
                << exchange_ptr->getArgs() << "');";
            if (!sql_helper.exec(sql.str(), nullptr, nullptr))
            {
                ELOG("ExchangeMapper insert error!");
                assert(0);
            }
        }
        void remove(const std::string &name)
        {
            std::stringstream sql;
            sql << "delete from exchange_table where name='" << name << "';";
            if (!sql_helper.exec(sql.str(), nullptr, nullptr))
            {
                ELOG("ExchangeMapper remove error!");
                assert(0);
            }
        }

        // 3.查询所有的Exchange,返回一个哈希表
        // 将数据库中的Exchange恢复到内存中,组织一个map并返回
        exchange_map recover()
        {
            exchange_map ret;
            std::stringstream sql;
            sql << "select * from exchange_table;";
            if (!sql_helper.exec(sql.str(), exchangeMapCb, &ret))
            {
                ELOG("ExchangeMapper recover error!");
                assert(0);
            }
            return ret;
        }

    private:
        static int exchangeMapCb(void *args, int rows, char **ret, char **fields)
        {
            Exchange::ptr exchange_ptr = std::make_shared<Exchange>();
            exchange_map *map_ptr = (exchange_map *)args;
            exchange_ptr->_name = ret[0];
            exchange_ptr->_type = (msg::ExchangeType)std::stoi(ret[1]);
            exchange_ptr->_durable = std::stoi(ret[2]);
            exchange_ptr->_auto_del = std::stoi(ret[3]);
            // 避免args为空时出错
            if (ret[4])
            {
                // ILOG("有其它参数,setArgs");
                // std::cout<<"ret[4]"<<ret[4]<<std::endl;
                exchange_ptr->setArgs(ret[4]);
            }
            else
            {
                ILOG("没有其它参数");
            }

            map_ptr->insert(std::make_pair(exchange_ptr->_name, exchange_ptr));
            return 0;
        }

    private:
        SqliteHelper sql_helper;
    };
    // 对外Exchange管理类
    class ExchangeManager
    {
    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        exchange_map _exchanges;

    public:
        using ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string &dbname)
            : _mapper(dbname)
        {
            _exchanges = _mapper.recover();
            // std::cout<<"recover后的个数"<<_exchanges.size()<<std::endl;
        }
        // 1.声明交换机,没有则创建
        bool declareExchange(const std::string &name, msg::ExchangeType type,
                             bool durable,
                             bool auto_del,
                             google::protobuf::Map<std::string, std::string> args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // std::cout<<"声明之前----"<<std::endl;
            // std::cout<<_exchanges.size()<<std::endl;

            auto it = _exchanges.find(name);
            if (it != _exchanges.end()) // 找到了
            {
                std::cout << _exchanges[name]->_args.size() << std::endl;
                ILOG("ExchangeManager declareExchange:%s already exists!", name.c_str());
                return true;
            }
            Exchange::ptr exchange_ptr = std::make_shared<Exchange>(name, type, durable, auto_del, args);
            // std::cout<<"打印的是构建出的对象"<<std::endl;
            // const auto &tmp = exchange_ptr->_args;
            // for(const auto &tmp : exchange_ptr->_args)
            // {
            //     std::cout<<"key:"<<tmp.first<<" value:"<<tmp.second<<std::endl;
            // }
            _exchanges.insert(std::make_pair(name, exchange_ptr));
            // 若持久化则插入数据库
            if (exchange_ptr->_durable == true)
                _mapper.insert(exchange_ptr);
            return true;
        }
        // 2.删除交换机
        bool removeExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end()) // 没找到
            {
                ILOG("ExchangeManager removeExchange not found!");
                return true;
            }
            // 删除交换机
            _exchanges.erase(it);
            // 若持久化则在数据库中也remove
            if (it->second->_durable)
                _mapper.remove(name);
            return true;
        }
        // 3.获取指定交换机/判断是否存在
        Exchange::ptr selectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end()) // 没找到返回空的ptr
                return Exchange::ptr();
            else
                return it->second;
        }
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end()) // 没找到
                return false;
            else
                return true;
        }
        // 4.清理数据结构
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _exchanges.clear();
            _mapper.dropTable();
        }
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }
    };
};

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值