让redis支持动态库
jopen
9年前
原文 http://wendal.net/2013/10/20.html
So, let’s put some fun in redis
redis的命令列表是写死在代码里面,编译后就没法修改(跟nginx一个德行)
硬编码一些额外的方法到redis中
最初写的一个hello world级的测试命令
void wendalCommand(redisClient *c) { struct timeval tv; // 从timeCommand拷贝的... addReplyMultiBulkLen(c,3); // 共返回3个结果 addReplyBulkCString(c, "Hi,Wendal"); // 输出个字符串啦 gettimeofday(&tv,NULL); // 获取时间, 也是从timeCommand拷贝的 addReplyBulkLongLong(c,tv.tv_sec); // 不解释了 addReplyBulkLongLong(c,tv.tv_usec); // 不解释了 }
然后在redisCommandTable中声明一个新的命令,就搞定了
{"wendal", wendalCommand,1,"rR",0,NULL,0,0,0,0,0}
做得更灵活?上动态库,哈哈
so,我声明了2个新的命令, 加载/卸载动态库
{"loadlib",loadlibCommand,2,"wmaR",0,NULL,0,0,0,0,0}, {"unloadlib",unloadlibCommand,2,"wmaR",0,NULL,0,0,0,0,0}
其中, 加载动态库,就是接受一个路径,并执行其redis_lib_init方法
// 简化版的loadlibCommand void loadlibCommand(redisClient *c) { void *handle; char *error; int (*redis_lib_init)(redisClient*, dict*); int re; handle = dlopen(c->argv[1]->ptr, RTLD_LAZY); if (!handle) { addReplyError(c, dlerror()); return; } redis_lib_init = dlsym(handle, "redis_lib_init"); // 查找redis_lib_init if ((error = dlerror()) != NULL) { dlclose(handle); addReplyError(c, error); return; } re = redis_lib_init(c, server.commands); // 执行之, 返回0就成功 if (re) { dlclose(handle); addReplyError(c, "lib init error"); return; } addReply(c,shared.ok); server.dirty ++; // 使dirty自增,这样就能同步到slave了 }
redis动态库示例
禁用flushdb命令
#include <redis.h> static void* flushdb; extern int redis_lib_init(redisClient *c) { flushdb = dictFetchValue(server.commands, sdsnew("FLUSHDB")); // 命令列表就是server.commands中,一个dict if (!flushdb) return 1; // 找不到? 被其他库删掉了? dictDeleteNoFree(server.commands, sdsnew("FLUSHDB")); // 删除但不要执行free return 0; } extern void redis_lib_depose(redisClient *c) { dictAdd(server.commands, sdsnew("FLUSHDB"), flushdb); // 卸载的时候就赋值回去,呵呵 return; }