天天看点

Redis中modules扩展模块的开发使用详解

本文和大家分享的主要是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);

  

  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的开销,又保证了原子性。

来源:峰云就她了