C++封装的Redis

#include "ServerBasePCH.h"
#include "RedisManager.h"

#ifdef _WIN32
#include 
#endif

RedisReply::RedisReply() : _reply(NULL) {
}

RedisReply::~RedisReply() {
	SetReply(NULL);
}

void RedisReply::SetReply(redisReply* r) {
	if (_reply != NULL) {
		freeReplyObject(_reply);
	}
	_reply = r;
}

Redis::Redis()
: m_pool_index(-1)
, m_c(NULL)
, m_pending_reply_count(0)
, m_host(NULL)
, m_port(0)
{
}

Redis::~Redis() {
	Close();

	if (m_host) {
		free(m_host);
		m_host = NULL;
	}
}

void Redis::SetPoolIndex(int index) {
	m_pool_index = index;
}

int Redis::GetPoolIndex() {
	return m_pool_index;
}

bool Redis::Connect(const char* host, unsigned int port) {
	m_pending_reply_count = 0;

	if (host != m_host) {
		if (m_host != NULL) {
			free(m_host);
		}
		m_host = (char*)calloc(strlen(host)+1, sizeof(char));
		memcpy(m_host, host, strlen(host));
	}

	m_port = port;
	NSLOG("Connecting to Redis `%s`...\n", host);

	m_c = redisConnect(host, port);
	if (m_c->err) {
		ESLOG("[redis] Connection error: %s\n", m_c->errstr);
		return false;
	}
	return true;
}

bool Redis::ReConnect() {
	Close();
	return Connect(m_host, m_port);
}

void Redis::Close() {  
	if (m_c != NULL) {
		redisFree(m_c);
		m_c = NULL;
	}
}

bool Redis::Ensure(bool *reconnected) {
	if (reconnected != NULL) {
		*reconnected = false;
	}

	if (m_c == NULL || m_c->err != 0) {
		if (reconnected != NULL) {
			*reconnected = true;
		}
		return ReConnect();
	}
	return true;
}

bool Redis::Ping()
{
	return ExecuteCommand(NULL, "PING");
}

bool Redis::ExecuteCommand(RedisReply &reply, const char *format, ...) {
	va_list ap;
	va_start(ap, format);
	bool ret = ExecuteCommandV(&reply, format, ap);
	va_end(ap);
	return ret;
}

bool Redis::ExecuteCommand(RedisReply *reply, const char *format, ...) {
	va_list ap;
	va_start(ap, format);
	bool ret = ExecuteCommandV(reply, format, ap);
	va_end(ap);
	return ret;
}

bool Redis::ExecuteCommandV(RedisReply *reply, const char *format, va_list ap) {
	if (!Ensure()) {
		return false;
	}

	redisReply* r = (redisReply*)redisvCommand(m_c, format, ap);
	if (r == NULL) {
		if (ReConnect()) {
			r = (redisReply*)redisvCommand(m_c, format, ap);
		}
	}

	if (r == NULL) {
		return false;
	}

	if (reply != NULL) {
		reply->SetReply(r);
	} else {
		freeReplyObject(r);
	}
	return true;
}


bool Redis::ExecuteCommandArgv(RedisReply *reply, int argc, const char **argv, const size_t *argvlen) {
	if (!Ensure()) {
		return false;
	}

	redisReply* r = (redisReply*)redisCommandArgv(m_c, argc, argv, argvlen);
	if (r == NULL) {
		if (ReConnect()) {
			r = (redisReply*)redisCommandArgv(m_c, argc, argv, argvlen);
		}
	}

	if (r == NULL) {
		return false;
	}

	if (reply != NULL) {
		reply->SetReply(r);
	} else {
		freeReplyObject(r);
	}
	return true;
}

bool Redis::ExecuteCommandInPipeline(const char *format, ...) {
	va_list ap;
	va_start(ap, format);
	bool ret = ExecuteCommandInPipelineV(format, ap);
	va_end(ap);
	return ret;
}

bool Redis::ExecuteCommandInPipelineV(const char *format, va_list ap) {
	if (!Ensure()) {
		return false;
	}

	int r = redisvAppendCommand(m_c, format, ap);
	if (r == REDIS_ERR) {
		if (ReConnect()) {
			r = redisAppendCommand(m_c, format, ap);
		}
	}

	m_pending_reply_count++;

	if (r == REDIS_ERR) {
		GetReplyInPipeline(NULL);
		return false;
	}

	return true;
}

bool Redis::ExecuteCommandInPipelineArgv(int argc, const char **argv, const size_t *argvlen) {
	if (!Ensure()) {
		return false;
	}

	int r = redisAppendCommandArgv(m_c, argc, argv, argvlen);
	if (r == REDIS_ERR) {
		if (ReConnect()) {
			r = redisAppendCommandArgv(m_c, argc, argv, argvlen);
		}
	}

	m_pending_reply_count++;

	if (r == REDIS_ERR) {
		GetReplyInPipeline(NULL);
		return false;
	}

	return true;
}

bool Redis::GetReplyInPipeline(RedisReply &reply) {
	return GetReplyInPipeline(&reply);
}

bool Redis::GetReplyInPipeline(RedisReply *reply) {
	bool reconnected = false;
	if (!Ensure(&reconnected) || reconnected == true || m_pending_reply_count <= 0) {
		// prevent getreply block current thread when connection reconnected.
		return false;
	}

	m_pending_reply_count--;

	redisReply *r = NULL;
	if (redisGetReply(m_c, (void**)&r) != REDIS_OK) {
		return false;
	}

	if (reply != NULL) {
		reply->SetReply(r);
	} else {
		freeReplyObject(r);
	}
	return true;
}

bool Redis::GetReply(RedisReply *reply) {
	bool reconnected = false;
	if (!Ensure(&reconnected) || reconnected == true) {
		// prevent getreply block current thread when connection reconnected.
		return false;
	}

	redisReply *r = NULL;
	if (redisGetReply(m_c, (void**)&r) != REDIS_OK) {
		return false;
	}

	if (reply != NULL) {
		reply->SetReply(r);
	} else {
		freeReplyObject(r);
	}
	return true;
}


RedisManager::RedisManager() 
: m_host(NULL)
, m_pool_index(0)
, m_port(0)
, m_is_free(NULL)
, m_connections(NULL)
, m_maxConnections(0)
, m_countConnections(0)
{
}

RedisManager::~RedisManager() {
	if (m_connections != NULL) {
		for (int i=0; i= m_maxConnections) {
		ELOG("RedisManager: connection exceed max connection count %d", m_maxConnections);
		return NULL;
	}

	CAutoLock lock(&m_mutex_of_connection);
	Redis *redis = new Redis();
	if (!redis->Connect(m_host, m_port))
	{
		delete redis;
		return NULL;
	}

	m_connections[m_countConnections] = redis;
	m_is_free[m_countConnections] = true;
	redis->SetPoolIndex(m_countConnections);
	m_countConnections++;

	return redis;
}

bool RedisManager::Init(const char* host, uint32 port, int maxConnections, int initConnections)
{
#ifdef _WIN32
	w32initWinSock();
#endif

	m_host = (char*)calloc(strlen(host)+1, sizeof(char));
	memcpy(m_host, host, strlen(host));
	m_port = port;

	m_maxConnections = maxConnections;
	m_connections = new Redis*[m_maxConnections]();
	m_is_free = new bool[m_maxConnections]();

	while (initConnections-- > 0) {
		if (_NewConnection() == NULL) {
			return false;
		}
	}

	return true;
}

Redis* RedisManager::Get()
{
	Redis *redis = NULL;

	int maxRetryCount = m_countConnections;
	int iConn = -1;
	while(maxRetryCount--) {
		long _index = AtomicIncrement(&m_pool_index);

		int count = m_countConnections;
		int iConn = _index % count;

		if (m_is_free[iConn]) {
			m_is_free[iConn] = false;
			redis = m_connections[iConn];
			break;
		}
	}

	if (redis == NULL)
	{
		redis = _NewConnection();
		if (redis) {
			iConn = redis->GetPoolIndex();
			m_is_free[iConn] = false;
		} else {
			return Get();
		}
	}

	return redis;
}

void RedisManager::Put(Redis* redis)
{
	int iConn = redis->GetPoolIndex();
	m_is_free[iConn] = true;
}


#pragma once

#include 

class RedisReply : public SerBaseHeapObject {
	friend class Redis;

public:
	RedisReply();
	~RedisReply();

	inline redisReply* GetReply() const {
		return _reply;
	}

	inline bool Status() const {
		return _reply != NULL && _reply->type == REDIS_REPLY_STATUS;
	}

	inline bool Error() const {
		return _reply == NULL || _reply->type == REDIS_REPLY_ERROR;
	}

	inline bool Integer() const {
		return _reply != NULL && _reply->type == REDIS_REPLY_INTEGER;
	}

	inline bool Nil() const {
		return _reply != NULL && _reply->type == REDIS_REPLY_NIL;
	}

	inline bool String() const {
		return _reply != NULL && _reply->type == REDIS_REPLY_STRING && _reply->len > 0;
	}

	inline bool Array() const {
		return _reply != NULL && _reply->type == REDIS_REPLY_ARRAY && _reply->elements > 0;
	}

protected:
	void SetReply(redisReply* r);

protected:
	redisReply* _reply;
};

class Redis : public SerBaseHeapObject {
protected:
	redisContext*	m_c;
	int				m_pool_index;

	char*			m_host;
	uint32			m_port;

	int				m_pending_reply_count;

public:
	Redis();
	virtual ~Redis();

	virtual bool Connect(const char* Hostname, unsigned int port);
	virtual bool ReConnect();
	virtual void Close() ;

	void SetPoolIndex(int index);
	int GetPoolIndex();

	inline bool Ensure(bool *reconnected = NULL);
	bool Ping();
	
	bool ExecuteCommand(RedisReply &reply, const char *format, ...);
	bool ExecuteCommand(RedisReply *reply, const char *format, ...);
	bool ExecuteCommandV(RedisReply *reply, const char *format, va_list ap);
	bool ExecuteCommandArgv(RedisReply *reply, int argc, const char **argv, const size_t *argvlen);

	bool ExecuteCommandInPipeline(const char *format, ...);
	bool ExecuteCommandInPipelineV(const char *format, va_list ap);
	bool ExecuteCommandInPipelineArgv(int argc, const char **argv, const size_t *argvlen);

	bool GetReplyInPipeline(RedisReply &reply);
	bool GetReplyInPipeline(RedisReply *reply);

	bool GetReply(RedisReply *reply);

	inline bool Error() {
		return m_c != NULL && m_c->err != 0;
	}

	inline char* GetError() {
		if (!Error()) return NULL;
		return m_c->errstr;
	}
};

class RedisManager : public Singleton {
	friend class Singleton;

protected:
	
	~RedisManager();

private:
	RedisManager();
	Mutex		m_mutex_of_connection;
	char*		m_host;
	uint32		m_port;
	int			m_maxConnections;
	int			m_countConnections;

	volatile long m_pool_index;

	Redis**		m_connections;
	bool*		m_is_free;

	Redis* _NewConnection();

public:
	bool Init(const char* host, uint32 port, int maxConnections, int initConnections);

	Redis* Get();
	void   Put(Redis* redis);
};

#define sRedisManager (*RedisManager::instance())

文章转载 http://www.cp2012.com/forum.php?mod=viewthread&tid=68&extra=page%3D1

你可能感兴趣的:(C/C++)