Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6796699
  • 博文数量: 578
  • 博客积分: 13065
  • 博客等级: 上将
  • 技术积分: 10103
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-26 16:44
个人简介

推荐: blog.csdn.net/aquester https://github.com/eyjian https://www.cnblogs.com/aquester http://blog.chinaunix.net/uid/20682147.html

文章分类

全部博文(578)

分类: 云计算

2018-10-31 16:16:28

实现一个Redis module,支持两个扩展命令:
1) 可同时对hash的多个field进行incr操作;
2) incrby同时设置一个key的过期时间

在没有module之前,需要借助eval+lua实现相同的功能。有了module,不但可以实现逻辑复杂,且性能高的扩展,同时享受Redis的持久化和容灾能力。

  1. // Redis命令扩展module
  2. #include "redismodule.h"
  3. #include <errno.h>
  4. #include <limits.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <vector>

  8. // 带超时的INCRBY命令
  9. // 格式:INCRBYEX KEY SECONDS INCREMENT
  10. //
  11. // 示例:
  12. // ex.incrbyex k1 10 1
  13. // ex.incrbyex k1 10 2
  14. int incrbyex_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  15.     // When automatic memory management is enabled:
  16.     // 1) don't need to close open keys
  17.     // 2) don't need to free replies
  18.     // 3) don't need to free RedisModuleString objects
  19.     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
  20.     if (argc != 4) return RedisModule_WrongArity(ctx);

  21.     RedisModuleKey *key = (RedisModuleKey*)RedisModule_OpenKey(ctx, argv[1],
  22.             REDISMODULE_READ|REDISMODULE_WRITE);
  23.     int type = RedisModule_KeyType(key);
  24.     if (type != REDISMODULE_KEYTYPE_STRING &&
  25.         type != REDISMODULE_KEYTYPE_EMPTY)
  26.     {
  27.         return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  28.     }

  29.     RedisModuleString* seconds = argv[2];
  30.     RedisModuleString* increment = argv[3];
  31.     long long ll_seconds; // 过期时长
  32.     long long ll_newval; // 新的值
  33.     if (RedisModule_StringToLongLong(seconds, &ll_seconds) != REDISMODULE_OK) {
  34.         return RedisModule_ReplyWithError(ctx, "ERR value is not an integer or out of range");
  35.     }
  36.     if (RedisModule_StringToLongLong(increment, &ll_newval) != REDISMODULE_OK) {
  37.         return RedisModule_ReplyWithError(ctx, "ERR value is not an integer or out of range");
  38.     }

  39.     size_t len;
  40.     char *s = RedisModule_StringDMA(key, &len, REDISMODULE_READ|REDISMODULE_WRITE);
  41.     if (0 == len || NULL == s || s == '\0') {
  42.         // set必须在Expire之前,否则会冲掉Expire的作用,
  43.         // 这也是else分支未用RedisModule_StringSet的原因
  44.         RedisModule_StringSet(key, increment);
  45.         RedisModule_SetExpire(key, ll_seconds*1000); // 以秒为单位,需要乘以1000
  46.     }
  47.     else {
  48.         char* endptr;
  49.         long long ll_oldval = strtoll(s, &endptr, 10); // s不一定是有效的数字,所以需要做检查
  50.         ll_newval = ll_newval + ll_oldval;
  51.         if ((errno == ERANGE && (ll_oldval == LLONG_MAX || ll_oldval == LLONG_MIN))
  52.                 || (errno != 0 && ll_oldval == 0)) {
  53.             return RedisModule_ReplyWithError(ctx, "ERR value is not an integer or out of range");
  54.         }
  55.         if (endptr == s || *endptr != '\0') {
  56.             return RedisModule_ReplyWithError(ctx, "ERR value is not an integer or out of range");
  57.         }

  58.         size_t newval_len;
  59.         RedisModuleString* newval = RedisModule_CreateStringFromLongLong(ctx, ll_newval);
  60.         const char* newval_s = RedisModule_StringPtrLen(newval, &newval_len);
  61.         if (newval_len > len)
  62.             RedisModule_StringTruncate(key, newval_len);
  63.         strncpy(s, newval_s, newval_len);
  64.     }

  65.     RedisModule_ReplyWithLongLong(ctx, ll_newval);
  66.     return REDISMODULE_OK;
  67. }

  68. // 实现命令HMINCRBY,同时对HASH的多个field值进行增减操作
  69. // 格式:HMINCRBY KEY FIELD1 VALUE1 FIELD2 VALUE2 FIELD3 VALUE3 ......
  70. //
  71. // 示例:
  72. // hmincrby k1 f1 1 f2 2
  73. // hmincrby k1 f5 1 f6 2 f7 3
  74. int hmincrby_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  75.     // When automatic memory management is enabled:
  76.     // 1) don't need to close open keys
  77.     // 2) don't need to free replies
  78.     // 3) don't need to free RedisModuleString objects
  79.     RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
  80.     if (argc < 4 || argc % 2 != 0) return RedisModule_WrongArity(ctx);

  81.     RedisModuleKey *key = (RedisModuleKey*)RedisModule_OpenKey(ctx, argv[1],
  82.             REDISMODULE_READ|REDISMODULE_WRITE);
  83.     int type = RedisModule_KeyType(key);
  84.     if (type != REDISMODULE_KEYTYPE_HASH &&
  85.         type != REDISMODULE_KEYTYPE_EMPTY)
  86.     {
  87.         return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  88.     }

  89.     const int count = argc/2 - 1; // 键值对个数
  90.     std::vector<long long> newval_array(count); // 用来存储新值的数组
  91.     for (int i=2; i<argc; i+=2) {
  92.         RedisModuleString* field = argv[i];
  93.         RedisModuleString* incrvalue = argv[i+1];
  94.         long long ll_newvalue;
  95.         if (RedisModule_StringToLongLong(incrvalue, &ll_newvalue) != REDISMODULE_OK) {
  96.             return RedisModule_ReplyWithError(ctx, "ERR value is not an integer or out of range");
  97.         }

  98.         RedisModuleString *oldval;
  99.         RedisModule_HashGet(key, REDISMODULE_HASH_NONE, field, &oldval, NULL);
  100.         if (NULL == oldval) { // field不存在时
  101.             RedisModule_HashSet(key,REDISMODULE_HASH_NONE, field, incrvalue, NULL);
  102.         }
  103.         else { // field已存在时
  104.             long long ll_oldval;
  105.             if (RedisModule_StringToLongLong(oldval, &ll_oldval) != REDISMODULE_OK) {
  106.                 return RedisModule_ReplyWithError(ctx, "ERR hash value is not an integer");
  107.             }

  108.             ll_newvalue = ll_newvalue + ll_oldval; // 累加得到新值
  109.             RedisModuleString* newval = RedisModule_CreateStringFromLongLong(ctx, ll_newvalue);
  110.             RedisModule_HashSet(key,REDISMODULE_HASH_NONE, field, newval, NULL);
  111.         }

  112.         newval_array[i] = ll_newvalue;
  113.     }

  114.     RedisModule_ReplyWithArray(ctx, count); // 返回数组类型的Reply
  115.     for (std::vector<long long>::size_type i=0; i<newval_array.size(); ++i)
  116.         RedisModule_ReplyWithLongLong(ctx, newval_array[i]);
  117.     return REDISMODULE_OK;
  118. }

  119. extern "C"
  120. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  121.     if (RedisModule_Init(ctx, "command_extension", 1, REDISMODULE_APIVER_1)
  122.         == REDISMODULE_ERR) return REDISMODULE_ERR;

  123.     /* Log the list of parameters passing loading the module. */
  124.     for (int j=0; j<argc; ++j) {
  125.         const char *s = RedisModule_StringPtrLen(argv[j], NULL);
  126.         printf("Module loaded with ARGV[%d] = %s\n", j, s);
  127.     }

  128.     if (RedisModule_CreateCommand(ctx, "ex.incrbyex",
  129.             incrbyex_RedisCommand,"write", 1, 1, 1) == REDISMODULE_ERR)
  130.         return REDISMODULE_ERR;

  131.     if (RedisModule_CreateCommand(ctx, "ex.hmincrby",
  132.             hmincrby_RedisCommand,"write", 1, 1, 1) == REDISMODULE_ERR)
  133.         return REDISMODULE_ERR;
  134.     return REDISMODULE_OK;
  135. }

阅读(10316) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册