Redis开源库ACL_CPP封装

        本文基于ACL_CPP,提供对Redis操作的封装。ACL_CPP是一个C++库,用于与Redis进行交互。它提供了一组类和函数,用于执行各种Redis命令和操作。该库基于BSD许可证,具有良好的跨平台支持,可用于多种操作系统和编译器。

特性:

  • ACL_CPP:
    • 提供了全面的Redis命令支持
    • 支持多种数据类型(字符串、列表、集合等)
    • 支持事务和管道操作
    • 支持发布/订阅模式
    • 提供连接池和负载均衡功能

优点:

  • ACL_CPP:
    • 使用C++语言,符合面向对象的设计理念
    • 提供了很多的高级功能,如事务和管道操作
    • 支持丰富的数据类型和Redis命令
    • 具有良好的跨平台支持

缺点:

  • ACL_CPP:
    • 学习曲线可能较陡峭,需要熟悉C++语言和Redis命令
#ifdef _WIN32
#include <WinSock2.h>
#endif
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <list>
#include <vector>
#include <future>
#include <iostream>
#include <unordered_map>

#include "acl_cpp/lib_acl.hpp"
#include "lib_acl.h"

#define MAX_CONNECTION_NUM (5)

enum class RedisCmdType {
    RedisCmdType_SET = 1,
	RedisCmdType_GET,
	RedisCmdType_INCR,
	RedisCmdType_HGET,
	RedisCmdType_HSET,
	RedisCmdType_HSETFV,
	RedisCmdType_HSETFVSYNC,
	RedisCmdType_HDEL,
	RedisCmdType_EXPIRE,
	RedisCmdType_SNDLIST,
	RedisCmdType_RECVLIST,
	RedisCmdType_RECVLISTNOWAIT,
	RedisCmdType_GETLISTSIZE
};

// 封装类 RedisCache
class RedisCache
{
public:
static void Enable() {
	LocalRedis::inst = new LocalRedis();
}

static int GetListSize(const string &key) {
	return LocalRedis::instance()->getListSize(key);
}

static void SendList(const string &key, const string &buffer, int timeOut) {
	LocalRedis::instance()->sendList(key, buffer, timeOut);
}

static string RecvList(const string &key, int t) {
	return LocalRedis::instance()->recvList(key, t);
}

static string RecvList(const string &key) {
	return LocalRedis::instance()->recvList(key);
}

static string Get(const string &key) {
	return LocalRedis::instance()->get(key);
}

static std::map<string, string> Hget(const string &key) {
	return LocalRedis::instance()->hget(key);
}

static void Set(const string &key, const string &value) {
	LocalRedis::instance()->set(key, value);
}

static void Hset(const string &key, const string &field, const string &value, int timeOut) {
	LocalRedis::instance()->hset(key, field, value, timeOut);
}

static void Hset(const string &key, std::map<string, string> &fv, int timeOut) {
	LocalRedis::instance()->hset(key, fv, timeOut);
}

static void HsetSync(const string &key, std::map<string, string> &fv, int timeOut) {
	LocalRedis::instance()->hsetSync(key, fv, timeOut);
}

static void Hdel(const string &key, const string &field) {
	LocalRedis::instance()->hdel(key, field);
}

static void Expire(const string &key, int timeOut) {
	LocalRedis::instance()->expire(key, timeOut);
}

static int Incr(const string &key, int begin, int end) {
	return LocalRedis::instance()->incr(key, begin, end);
}
};

class ClientTh {
public:
	ClientTh(acl::redis_client_cluster& cluster, LocalRedis::Queue &queue)
	: cluster_(cluster)
	, queue_(queue) {
		thread_ = new std::thread(std::bind(&ClientTh::MainLoop, this));
	}

	~ClientTh() {
		if (thread_) {
			delete thread_;
		}
	}

private:
	void MainLoop() {
		while(1) {
			while(1) {
				auto msg = queue_.get();
				try {
					acl::redis cmd;
					cmd.set_cluster(&cluster_, MAX_CONNECTION_NUM);
					
					switch (msg.cmd) {
					case RedisCmdType_SET:
						cmd.set(msg.key.c_str(), msg.value.c_str());					
						break;
					case RedisCmdType_GET:
						acl::string result;
						cmd.get(msg.key.c_str(), result);
						msg.prom->set_value(result.c_str());					
						break;
					case RedisCmdType_INCR:
						long long result = 0;
						cmd.incr(msg.key.c_str(), &result);
						msg.prom->set_value(std::to_string(result));
						break;
					case RedisCmdType_HGET:
						std::map<acl::string, acl::string> result;
						cmd.hgetall(msg.key.c_str(), result);
						msg.prom->set_value(std::to_string(result));
						break;
					case RedisCmdType_HSET:
						cmd.hset(msg.key.c_str(), msg.field.c_str(), msg.value.c_str());
						if (0 != msg.t) {
							cmd.expire(msg.key.c_str(), msg.t);
						}
						break;
					case RedisCmdType_HSETFV:
						std::map<acl::string, acl::string> fv;						
						for (auto iter = msg.fv.begin(); iter != msg.fv.end(); ++iter) {
							fv[iter->first.c_str()] = iter->second.c_str();
						}
						cmd.hmset(msg.key.c_str(), fv);
			
						if (0 != msg.t) {
							cmd.expire(msg.key.c_str(), msg.t);
						}
						break;
					case RedisCmdType_HSETFVSYNC:
						std::map<acl::string, acl::string> fv;
						for (auto iter = msg.fv.begin(); iter != msg.fv.end(); ++iter) {
							fv[iter->first.c_str()] = iter->second.c_str();
						}
						cmd.hmset(msg.key.c_str(), fv);

						if (0 != msg.t) {
							cmd.expire(msg.key.c_str(), msg.t);
						}
						msg.prom->set_value("");
						break;
					case RedisCmdType_HDEL:
						cmd.hdel(msg.key.c_str(), msg.field.c_str());
						break;
					case RedisCmdType_EXPIRE:
						if (0 != msg.t) {
							cmd.expire(msg.key.c_str(), msg.t);
						}					
						break;
					case RedisCmdType_SNDLIST:
						cmd.lpush(msg.key.c_str(), msg.value.c_str(), NULL);
						if (0 != msg.t) {
							cmd.expire(msg.key.c_str(), msg.t);
						}
						break;
					case RedisCmdType_RECVLIST:
						acl::string result;
						if (0 != msg.t) {
							cmd.rpop(msg.key.c_str(), result);
						}else {
							std::pair<acl::string, acl::string> result2;
							cmd.brpop(result2, msg.t, msg.key.c_str(), NULL);
							result = result2.second;
						}
						msg.prom->set_value(result.c_str());
						break;
					case RedisCmdType_RECVLISTNOWAIT:
						acl::string result;
						cmd.rpop(msg.key.c_str(), result);
						msg.prom->set_value(result.c_str());
						break;	
					case RedisCmdType_GETLISTSIZE:
						int result = cmd.llen(msg.key.c_str());
						msg.prom->set_value(std::to_string(result));
						break;
					default:
						break;
					}
				} catch (std::exception e) {
					queue_.setFront(msg);
					std::this_thread::sleep_for(std::chrono::milliseconds(1000));
					break;
				} catch (...) {
					queue_.setFront(msg);
					std::this_thread::sleep_for(std::chrono::milliseconds(1000));
					break;
				}
			}
		}
	}

private:
	std::thread *thread_;
	int port_;
	string host_;
	string password_;
	acl::redis_client_cluster& cluster_;
	LocalRedis::Queue &queue_;
};

class ClientMgr {
public:
	ClientMgr(const string &host, const int &port, const string &password, LocalRedis::Queue &queue)
	: host_(host)
	, port_(port)
	, password_(password)
	, queue_(queue) {
		cluster_.set((host_ + ":" + std::to_string(port_)).c_str(), MAX_CONNECTION_NUM, 10, 10);
		if ("" != password_) {
			cluster.set_password("default", password_.c_str());
		}

		for (int i = 0; MAX_CONNECTION_NUM > i; ++i) {
			clients_.push_back(createClient());
		}
	}

private:
	ClientTh* createClient() {
		std::unique_ptr<ClientTh> client(new ClientTh(cluster_, queue_));
		return client.release();
	}

private:
	std::mutex mutex_;
	std::list<ClientTh*> clients_;
	string host_;
	int port_;
	string password_;
	LocalRedis::Queue &queue_;
	acl::redis_client_cluster cluster_;
};

class Queue {
public:
	struct Msg {
		RedisCmdType cmd;
		string key;
		string field;
		string value;
		std::map<string, string> fv;
		int t;
		std::shared_ptr<std::promise<string>> prom;
	};
public:
	Msg get();
	void hset(const string &key, const string &field, const string &value, int timeOut);
	void hset(const string &key, const std::map<string, string> &fv, int timeOut);
	void expire(const string &key, int timeOut);
	void set(const RedisCmdType &cmd, const string &key, const string &value, int timeOut);
	void set(const RedisCmdType &cmd, const string &key, std::shared_ptr<std::promise<string> > prom, int t);
	void set(const Msg &m);
	void setFront(const Msg &m);
private:
	std::list<Msg> buffers;
	std::condition_variable cv;
	std::mutex mutex;
	std::mutex mutex2;
};
	
class LocalRedis
{
	friend class RedisCache;
public:
	LocalRedis();
	~LocalRedis();

	static LocalRedis *instance() {
		return inst;
	}

	int getListSize(const string &key);
	void sendList(const string &key, const string &buffer, int timeOut);
	string recvList(const string &key, int t);
	string recvList(const string &key);

	string get(const string &key);
	std::map<string, string> hget(const string &key);
	void set(const string &key, const string &value);
	void hset(const string &key, const string &field, const string &value, int timeOut);
	void hset(const string &key, const map<string, string> &fv, int timeOut);
	void hsetSync(const string &key, const map<string, string> &fv, int timeOut);
	void hdel(const string &key, const string &field);
	void expire(const string &key, int timeOut);
	int incr(const string &key, int begin, int end);

private:
	ClientMgr *ClientMgr;
	Queue write_queue_;

	std::condition_variable cv;
	std::mutex mutex;

	static LocalRedis *inst;
};

LocalRedis *LocalRedis::inst;

LocalRedis::Queue::Msg LocalRedis::Queue::get() {
	Msg msg;
	while (1) {
		{
			std::unique_lock<std::mutex> lock(mutex2);
			if (buffers.empty() == false) {
				msg = buffers.front();
				buffers.pop_front();
				return msg;
			}
		}
		{
			std::unique_lock<std::mutex> lock(mutex);
			cv.wait(lock);
		}
	}
}

void LocalRedis::Queue::hset(const string &key, const string &field, const string &value, int timeOut) {
	Msg msg;
	msg.cmd = RedisCmdType_HSET;
	msg.key = key;
	msg.field = field;
	msg.value = value;
	msg.t = timeOut;
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::hset(const string &key, const map<string, string> &fv, int timeOut) {
	Msg msg;
	msg.cmd = RedisCmdType_HSET;
	msg.key = key;
	msg.fv = fv;
	msg.t = timeOut;
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::expire(const string &key, int timeOut) {
	Msg msg;
	msg.cmd = RedisCmdType_EXPIRE;
	msg.key = key;
	msg.t = timeOut;
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::set(const RedisCmdType &cmd, const string &key, const string &value, int timeOut) {
	Msg msg;
	msg.cmd = cmd;
	msg.key = key;
	msg.value = value;
	msg.t = timeOut;
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::set(const RedisCmdType &cmd, const string &key, std::shared_ptr<std::promise<string> > prom, int t) {
	Msg msg;
	msg.cmd = cmd;
	msg.key = key;
	msg.prom = prom;
	msg.t = t;
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::set(const Msg &msg) {
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_back(msg);
	}
	cv.notify_one();
}

void LocalRedis::Queue::setFront(const Msg &m) {
	{
		std::unique_lock<std::mutex> lock(mutex2);
		buffers.push_front(m);
	}
	cv.notify_one();
}


LocalRedis::LocalRedis() {
	acl::acl_cpp_init();
	acl::log::stdout_open(true);

	client_mgr_ = new ClientMgr("127.0.0.1", 6379, "", write_queue_);
}


LocalRedis::~LocalRedis() {
	if (nullptr != client_mgr_) {
		delete client_mgr_;
	}
}

void LocalRedis::sendList(const string &key, const string &buffer, int timeOut) {
	write_queue_.set(RedisCmdType_SNDLIST, key, buffer, timeOut);
}

string LocalRedis::recvList(const string &key, int t) {
	std::shared_ptr<std::promise<string> > prom(new std::promise<string>());
	auto future = prom->get_future();
	write_queue_.set(RedisCmdType_RECVLIST, key, prom, t);
	int waitTime = max(t + 5, 5);
	if (std::future_status::ready != future.wait_for(std::chrono::seconds(waitTime))) {
		return "";
	}
	return future.get();
}

string LocalRedis::recvList(const string &key) {
	std::shared_ptr<std::promise<string> > prom(new std::promise<string>());
	auto future = prom->get_future();
	write_queue_.set(RedisCmdType_RECVLIST, key, prom, 0);
	if (std::future_status::ready != future.wait_for(std::chrono::seconds(5))) {
		return "";
	}
	return future.get();
}

void LocalRedis::set(const string &key, const string &value) {
	write_queue_.set(RedisCmdType_SET, key, value, 0);
}

void LocalRedis::hset(const string &key, const std::map<string, string> &fv, int timeOut) {
	write_queue_.hset(key, fv, timeOut);
}

void LocalRedis::hset(const string &key, const string &field, const string &value, int timeOut) {
	write_queue_.hset(key, field, value, timeOut);
}

void LocalRedis::hsetSync(const string &key, const std::map<string, string> &fv, int timeOut) {
	std::shared_ptr<std::promise<string>> prom(new std::promise<string>());
	auto future = prom->get_future();

	Queue::Msg msg;
	msg.cmd = RedisCmdType_HSETFVSYNC;
	msg.key = key;
	msg.fv = fv;
	msg.prom = prom;
	msg.t = 0;
	write_queue_.set(msg);

	future.wait_for(std::chrono::seconds(5));
}

void LocalRedis::hdel(const string &key, const string &field) {
	Queue::Msg msg;
	msg.cmd = RedisCmdType_HDEL;
	msg.key = key;
	msg.field = field;
	msg.t = 0;
	write_queue_.set(msg);
}

void LocalRedis::expire(const string &key, int timeOut) {
	write_queue_.expire(key, timeOut);
}

int LocalRedis::incr(const string &key, int begin, int end) {
	std::shared_ptr<std::promise<string>> prom(new std::promise<string>());
	auto future = prom->get_future();

	Queue::Msg msg;
	msg.cmd = RedisCmdType_INCR;
	msg.key = key;
	msg.field = std::to_string(begin);
	msg.value = std::to_string(end);
	msg.prom = prom;
	msg.t = 0;
	write_queue_.set(RedisCmdType_INCR, key, prom, 0);

	if (std::future_status::ready != future.wait_for(std::chrono::seconds(5))) {
		return begin;
	}
	unsigned int ret = std::atoi(future.get().c_str());
	ret = begin + (ret % (end - begin));

	return ret;
}

string LocalRedis::get(const string &key) {
	std::shared_ptr<std::promise<string>> prom(new std::promise<string>());
	auto future = prom->get_future();
	write_queue_.set(RedisCmdType_GET, key, prom, 0);
	if (std::future_status::ready != future.wait_for(std::chrono::seconds(5))) {
		return "";
	}
	return future.get();
}

map<string, string> LocalRedis::hget(const string &key) {
	map<string, string> ret;
	std::shared_ptr<std::promise<string>> prom(new std::promise<string>());
	auto future = prom->get_future();
	write_queue_.set(RedisCmdType_HGET, key, prom, 0);
	if (std::future_status::ready != future.wait_for(std::chrono::seconds(5))) {
		return ret;
	}
	string retStr = future.get();
	if (false == retStr.empty()) {
		// todo
	}
	return ret;
}

int LocalRedis::getListSize(const string &key) {
	std::shared_ptr<std::promise<string>> prom(new std::promise<string>());
	auto future = prom->get_future();
	write_queue_.set(RedisCmdType_GETLISTSIZE, key, prom, 0);
	if (std::future_status::ready != future.wait_for(std::chrono::seconds(5))) {
		return 0;
	}
	return atoi(future.get().c_str());
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值