本文和大家分享的主要是redis中modules扩展模块的开发与使用相关内容,希望通过本文的分享对大家学习redis 有所帮助,一起开看看吧。
首先我们要安装redis 4.0 rc 新版. antirez说过,在3.x版本中不会加入自定义模块加载的.
#xiaorui.cc
wget https://github.com/antirez/redis/archive/4.0-rc2.tar.gz
tar zxvf 4.0*cd 4.0makemake test
下载第三方的Redis modules模块,make编译
gitclonehttps://github.com/RedisLabsModules/redexcd redexmake
上面编译完了后,在src下是有一堆动态链接库so 文件的, 然后我们修改redis.conf的配置, 加入这些so文件。
--loadmodule /path/src/module.so
redisEx moudules的扩展基本是 在redis本身数据结构基础上做的调整 .
Includedmodules:
rxkeys - extendedkeyscommands (ModuleHubpage)
rxstrings - extendedStringscommands (ModuleHubpage)
rxhashes - extendedHashescommands (ModuleHubpage)
rxlists - extendedListscommands (ModuleHubpage)
rxsets - extendedSets commands (ModuleHubpage)
rxzsets - extendedSorted Sets commands (ModuleHubpage)
rxgeo - extendedGeoSets commands (ModuleHubpage)
我们看下RedisEx对 zset的相关调整,比如里面的zpop 和 zrevpop , 一看这名字我觉得大家就能感觉出来他是干嘛的吧?
redis 本身的zset 是没有pop命令的,如果你想获取并删除,那么就只能 zrange and zrem . zpop 是帮你pop出来一个最小score的数据,zrevpop 反之.
# xiaorui.cc
int ZPopGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
if (argc < 2 || argc > 3) {
return RedisModule_WrongArity(ctx);
}
RedisModule_AutoMemory(ctx);
/* Getthetargetcommand. */
size_tcmdlen;
constchar *cmd = RedisModule_StringPtrLen(argv[0], &cmdlen);
int rev = !strncasecmp("zrevpop", cmd, cmdlen);
int withscore = RMUtil_ArgExists("WITHSCORE", argv, argc, 2);
if ((argc == 3) && !withscore) return RedisModule_WrongArity(ctx);
// open thekeyand makesureit's indeed a ZSETand not empty
RedisModuleKey *key =
RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
// and emptykey - return null
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) {
RedisModule_ReplyWithNull(ctx);
return REDISMODULE_OK;
}
// 类型错误,抛出异常
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
return REDISMODULE_ERR;
}
// 获取最小score分值的元素
doublescore;
(rev ? RedisModule_ZsetLastInScoreRange : RedisModule_ZsetFirstInScoreRange)(
key, REDISMODULE_NEGATIVE_INFINITE, REDISMODULE_POSITIVE_INFINITE, 0, 0);
RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key, &score);
RedisModule_ZsetRangeStop(key);
// 删除这个元素
RedisModule_ZsetRem(key, ele, NULL);
// 返回元素 或者 含有分值 (取决于是否传入withscore参数)
RedisModule_ReplyWithArray(ctx, (withscore ? 2 : 1));
RedisModule_ReplyWithString(ctx, ele);
if (withscore) RedisModule_ReplyWithDouble(ctx, score);
return REDISMODULE_OK;
}
Redis set里多了一个 msismember的命令扩展,是个sismember的多扩展 . 用来判断多个集合里是否含有某个元素, 符合一个条件加 +1 , 如果返回 2 ,那么就是两个集合都含有这个元素.
redis> SADDadminsAliceBobxiaorui.cc
(integer) 3redis> SADDoncallZoeBobXavier
(integer) 3redis> MSISMEMBERadminsoncallAlice
(integer) 1redis> MSISMEMBERadminsoncallZoe
(integer) 1redis> MSISMEMBERadminsoncallBob
(integer) 2
Reids Msismember 命令源代码如下 :
#xiaorui.cc
int MSIsMemberCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc < 3) {
if (RedisModule_IsKeysPositionRequest(ctx))
return REDISMODULE_OK;
else
return RedisModule_WrongArity(ctx);
}
if (RedisModule_IsKeysPositionRequest(ctx)) {
size_t i;
for (i = 1; i < argc - 1; i++) RedisModule_KeyAtPos(ctx, i);
return REDISMODULE_OK;
}
RedisModule_AutoMemory(ctx);
int iele = argc - 1;
size_tcount = 0;
int i;
for (i = 1; i < iele; i++) {
RedisModuleKey *key =
RedisModule_OpenKey(ctx, argv[i], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) continue;
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_SET) { // 判断数据类型
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
return REDISMODULE_ERR;
}
RedisModuleCallReply *rep =
RedisModule_Call(ctx, "SISMEMBER", "ss", argv[i], argv[iele]); // 循环遍历调用 sismember 查看set集合中是否含有该元素
RMUTIL_ASSERT_NOERROR(rep)
count += RedisModule_CallReplyInteger(rep); // 如何一个就加一个数
}
RedisModule_ReplyWithLongLong(ctx, count); //返回
return REDISMODULE_OK;
}
通过上面几个redis扩展源码我们发现,基本都是多个命令合并成一个函数,对于客户端来说节省了网络io的开销,又保证了原子性。
来源:峰云就她了
首先我们要安装redis 4.0 rc 新版. antirez说过,在3.x版本中不会加入自定义模块加载的.
#xiaorui.cc
wget https://github.com/antirez/redis/archive/4.0-rc2.tar.gz
tar zxvf 4.0*cd 4.0makemake test
下载第三方的Redis modules模块,make编译
gitclonehttps://github.com/RedisLabsModules/redexcd redexmake
上面编译完了后,在src下是有一堆动态链接库so 文件的, 然后我们修改redis.conf的配置, 加入这些so文件。
--loadmodule /path/src/module.so
redisEx moudules的扩展基本是 在redis本身数据结构基础上做的调整 .
Includedmodules:
rxkeys - extendedkeyscommands (ModuleHubpage)
rxstrings - extendedStringscommands (ModuleHubpage)
rxhashes - extendedHashescommands (ModuleHubpage)
rxlists - extendedListscommands (ModuleHubpage)
rxsets - extendedSets commands (ModuleHubpage)
rxzsets - extendedSorted Sets commands (ModuleHubpage)
rxgeo - extendedGeoSets commands (ModuleHubpage)
我们看下RedisEx对 zset的相关调整,比如里面的zpop 和 zrevpop , 一看这名字我觉得大家就能感觉出来他是干嘛的吧?
redis 本身的zset 是没有pop命令的,如果你想获取并删除,那么就只能 zrange and zrem . zpop 是帮你pop出来一个最小score的数据,zrevpop 反之.
# xiaorui.cc
int ZPopGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
if (argc < 2 || argc > 3) {
return RedisModule_WrongArity(ctx);
}
RedisModule_AutoMemory(ctx);
/* Getthetargetcommand. */
size_tcmdlen;
constchar *cmd = RedisModule_StringPtrLen(argv[0], &cmdlen);
int rev = !strncasecmp("zrevpop", cmd, cmdlen);
int withscore = RMUtil_ArgExists("WITHSCORE", argv, argc, 2);
if ((argc == 3) && !withscore) return RedisModule_WrongArity(ctx);
// open thekeyand makesureit's indeed a ZSETand not empty
RedisModuleKey *key =
RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_ZSET) {
// and emptykey - return null
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) {
RedisModule_ReplyWithNull(ctx);
return REDISMODULE_OK;
}
// 类型错误,抛出异常
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
return REDISMODULE_ERR;
}
// 获取最小score分值的元素
doublescore;
(rev ? RedisModule_ZsetLastInScoreRange : RedisModule_ZsetFirstInScoreRange)(
key, REDISMODULE_NEGATIVE_INFINITE, REDISMODULE_POSITIVE_INFINITE, 0, 0);
RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key, &score);
RedisModule_ZsetRangeStop(key);
// 删除这个元素
RedisModule_ZsetRem(key, ele, NULL);
// 返回元素 或者 含有分值 (取决于是否传入withscore参数)
RedisModule_ReplyWithArray(ctx, (withscore ? 2 : 1));
RedisModule_ReplyWithString(ctx, ele);
if (withscore) RedisModule_ReplyWithDouble(ctx, score);
return REDISMODULE_OK;
}
Redis set里多了一个 msismember的命令扩展,是个sismember的多扩展 . 用来判断多个集合里是否含有某个元素, 符合一个条件加 +1 , 如果返回 2 ,那么就是两个集合都含有这个元素.
redis> SADDadminsAliceBobxiaorui.cc
(integer) 3redis> SADDoncallZoeBobXavier
(integer) 3redis> MSISMEMBERadminsoncallAlice
(integer) 1redis> MSISMEMBERadminsoncallZoe
(integer) 1redis> MSISMEMBERadminsoncallBob
(integer) 2
Reids Msismember 命令源代码如下 :
#xiaorui.cc
int MSIsMemberCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc < 3) {
if (RedisModule_IsKeysPositionRequest(ctx))
return REDISMODULE_OK;
else
return RedisModule_WrongArity(ctx);
}
if (RedisModule_IsKeysPositionRequest(ctx)) {
size_t i;
for (i = 1; i < argc - 1; i++) RedisModule_KeyAtPos(ctx, i);
return REDISMODULE_OK;
}
RedisModule_AutoMemory(ctx);
int iele = argc - 1;
size_tcount = 0;
int i;
for (i = 1; i < iele; i++) {
RedisModuleKey *key =
RedisModule_OpenKey(ctx, argv[i], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) continue;
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_SET) { // 判断数据类型
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
return REDISMODULE_ERR;
}
RedisModuleCallReply *rep =
RedisModule_Call(ctx, "SISMEMBER", "ss", argv[i], argv[iele]); // 循环遍历调用 sismember 查看set集合中是否含有该元素
RMUTIL_ASSERT_NOERROR(rep)
count += RedisModule_CallReplyInteger(rep); // 如何一个就加一个数
}
RedisModule_ReplyWithLongLong(ctx, count); //返回
return REDISMODULE_OK;
}
通过上面几个redis扩展源码我们发现,基本都是多个命令合并成一个函数,对于客户端来说节省了网络io的开销,又保证了原子性。
来源:峰云就她了