您当前的位置: 首页 >  redis

qianbo_insist

暂无认证

  • 0浏览

    0关注

    399博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

hiredis源码分析与简单封装

qianbo_insist 发布时间:2021-06-26 07:46:51 ,浏览量:0

hiredis

Hiredis是一个开源C库函数,提供了基本的操作redis 函数, 如数据库连接、发送命令、释放资源等等 hiredis

1、hiredis net

hiredis 本身就是做了跨平台的代码,c语言打造可以执行在多种平台上,看看他的net块做了些什么

#include "fmacros.h"
#include 
#ifdef _WIN32
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#else
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#endif
#include 
#include 
#include 
#include 
#include 
#ifndef _WIN32
#include 
#endif
#include 

#include "net.h"
#include "sds.h"
#ifdef _WIN32
#include "../src/win32fixes.h"
#endif

看他的头文件,分析一下,linux下是使用poll 和 epoll方式的,windows下使用select 和IOCP 异步方式,对iocp的封装在win32_iocp.h 和win32_iocp.c 里面对于客户端来说,poll方式是可以了,比select方式效率还是要高,不过poll在windows和linux操作系统上还是可以使用封装来通用的。所以里面还有一个asycn 封装模块,异步回调。c语言写的东西确实简单易懂。

2、线程锁和互斥

来看一下他对加锁方面的写法,实际上,在windows上使用了api互斥变量,在linux上使用pthread,通用做法,这对做数据库系统客户端来说是很有帮助的,简化编程,在windows上直接调用锁api方式效率更高。

#define pthread_mutex_t CRITICAL_SECTION
#define pthread_attr_t ssize_t

#define pthread_mutex_init(a,b) (InitializeCriticalSectionAndSpinCount((a), 0x80000400),0)
#define pthread_mutex_destroy(a) DeleteCriticalSection((a))
#define pthread_mutex_lock EnterCriticalSection
#define pthread_mutex_unlock LeaveCriticalSection

#define pthread_equal(t1, t2) ((t1) == (t2))

#define pthread_attr_init(x) (*(x) = 0)
#define pthread_attr_getstacksize(x, y) (*(y) = *(x))
#define pthread_attr_setstacksize(x, y) (*(x) = y)

#define pthread_t u_int
3、hash
typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;

typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;
3.1 hash 函数
/* Generic hash function (a popular one from Bernstein).
 * I tested a few and this was the best. */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
    unsigned int hash = 5381;

    while (len--)
        hash = ((hash table[index];
    ht->table[index] = entry;

    /* Set the hash entry fields. */
    dictSetHashKey(ht, entry, key);
    dictSetHashVal(ht, entry, val);
    ht->used++;
    return DICT_OK;
}

这个对于使用c语言的程序员最熟悉不过了,实际上就是hash-》链表,寻址,检测冲突,增加,挂链表。整个hash表操作增删改查,400多行代码,精简,效率好。

4、 链表
typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

typedef struct listIter {
    listNode *next;
    int direction;
} listIter;

typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
    unsigned long len;
} list;

/* Functions implemented as macros */
#define listLength(l) ((l)->len)
#define listFirst(l) ((l)->head)
#define listLast(l) ((l)->tail)
#define listPrevNode(n) ((n)->prev)
#define listNextNode(n) ((n)->next)
#define listNodeValue(n) ((n)->value)

#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))

#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)

/* Prototypes */
list *listCreate(void);
void listRelease(list *list);
list *listAddNodeHead(list *list, void *value);
list *listAddNodeTail(list *list, void *value);
list *listInsertNode(list *list, listNode *old_node, void *value, int after);
void listDelNode(list *list, listNode *node);
listIter *listGetIterator(list *list, int direction);
listNode *listNext(listIter *iter);
void listReleaseIterator(listIter *iter);
list *listDup(list *orig);
listNode *listSearchKey(list *list, void *key);
listNode *listIndex(list *list, long index);
void listRewind(list *list, listIter *li);
void listRewindTail(list *list, listIter *li);
void listRotate(list *list);

链表加尾

list *listAddNodeTail(list *list, void *value)
{
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    node->value = value;
    if (list->len == 0) {
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        node->prev = list->tail;
        node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    list->len++;
    return list;
}

链表操作简直就是数据结构课程基础课,如果读者是年轻的程序员,无论是使用java,c,c++,还是其他语言的使用者,这个模块可以作为通用学习模块。

5、ae

ae是hiredis的一个事件消息loop模块,被封装在ae.h 和ae.cpp 中 下面是一个文件创建消息的eventloop

int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData)
{
    aeFileEvent *fe;
    if (fd >= eventLoop->setsize) {
        errno = ERANGE;
        return AE_ERR;
    }
    fe = &eventLoop->events[fd];

    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;
    fe->mask |= mask;
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    fe->clientData = clientData;
    if (fd > eventLoop->maxfd)
        eventLoop->maxfd = fd;
    return AE_OK;
}

还有iocp的事件,epoll事件,时间事件等等。

总结

总的来说,对于做一个数据库系统来说,无论是客户端还是服务器端,都有很多需要我们做的,做一个精品需要我们在细节上下更多的功夫。

封装

简单用c++ 封装一下,更容易使用

#ifndef _REDIS_CLIENT_H_
#define _REDIS_CLIENT_H_
#include "../hiredis/hiredis.h"
#include 
#include 
using namespace std;

class Redis
{
public:
	Redis();
	~Redis();
public:
	int Connect(const char * ip, int port);
	void disConnect();
public:
	void setString(const string & key, const string & value);
	void setString(const string & key, const int & value);
	void setString(const string & key, const float & value);
	bool SetBinary(const string & key, void* pData, int dataLen);
	bool GetBinary(const string & key, void*pData, int datalen);
private:
	void setString(const string & data);
public:
	void getString(const string & key, string & value);
	void getString(const string & key, int & value);
	void getString(const string & key, float & value);
private:
	void getString(const string & key);
private:
	void freeReply();
	bool isError();
private:

	redisContext * _context = NULL;
	redisReply * _reply = NULL;
	string _ip;
	int _port;
};
#include "redisclient.h"

#include 
#include 
#include 
#include 

using std::cout;
using std::endl;
using std::stringstream;
#define SETSTRING(key, value) \
stringstream ss;\
ss             
关注
打赏
1663161521
查看更多评论
0.0395s