datatype.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /* This module current tests a small subset but should be extended in the future
  2. * for general ModuleDataType coverage.
  3. */
  4. #include "redismodule.h"
  5. static RedisModuleType *datatype = NULL;
  6. static int load_encver = 0;
  7. #define DATATYPE_ENC_VER 1
  8. typedef struct {
  9. long long intval;
  10. RedisModuleString *strval;
  11. } DataType;
  12. static void *datatype_load(RedisModuleIO *io, int encver) {
  13. load_encver = encver;
  14. int intval = RedisModule_LoadSigned(io);
  15. if (RedisModule_IsIOError(io)) return NULL;
  16. RedisModuleString *strval = RedisModule_LoadString(io);
  17. if (RedisModule_IsIOError(io)) return NULL;
  18. DataType *dt = (DataType *) RedisModule_Alloc(sizeof(DataType));
  19. dt->intval = intval;
  20. dt->strval = strval;
  21. return dt;
  22. }
  23. static void datatype_save(RedisModuleIO *io, void *value) {
  24. DataType *dt = (DataType *) value;
  25. RedisModule_SaveSigned(io, dt->intval);
  26. RedisModule_SaveString(io, dt->strval);
  27. }
  28. static void datatype_free(void *value) {
  29. if (value) {
  30. DataType *dt = (DataType *) value;
  31. if (dt->strval) RedisModule_FreeString(NULL, dt->strval);
  32. RedisModule_Free(dt);
  33. }
  34. }
  35. static void *datatype_copy(RedisModuleString *fromkey, RedisModuleString *tokey, const void *value) {
  36. const DataType *old = value;
  37. /* Answers to ultimate questions cannot be copied! */
  38. if (old->intval == 42)
  39. return NULL;
  40. DataType *new = (DataType *) RedisModule_Alloc(sizeof(DataType));
  41. new->intval = old->intval;
  42. new->strval = RedisModule_CreateStringFromString(NULL, old->strval);
  43. /* Breaking the rules here! We return a copy that also includes traces
  44. * of fromkey/tokey to confirm we get what we expect.
  45. */
  46. size_t len;
  47. const char *str = RedisModule_StringPtrLen(fromkey, &len);
  48. RedisModule_StringAppendBuffer(NULL, new->strval, "/", 1);
  49. RedisModule_StringAppendBuffer(NULL, new->strval, str, len);
  50. RedisModule_StringAppendBuffer(NULL, new->strval, "/", 1);
  51. str = RedisModule_StringPtrLen(tokey, &len);
  52. RedisModule_StringAppendBuffer(NULL, new->strval, str, len);
  53. return new;
  54. }
  55. static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  56. if (argc != 4) {
  57. RedisModule_WrongArity(ctx);
  58. return REDISMODULE_OK;
  59. }
  60. long long intval;
  61. if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) {
  62. RedisModule_ReplyWithError(ctx, "Invalid integer value");
  63. return REDISMODULE_OK;
  64. }
  65. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  66. DataType *dt = RedisModule_Calloc(sizeof(DataType), 1);
  67. dt->intval = intval;
  68. dt->strval = argv[3];
  69. RedisModule_RetainString(ctx, dt->strval);
  70. RedisModule_ModuleTypeSetValue(key, datatype, dt);
  71. RedisModule_CloseKey(key);
  72. RedisModule_ReplyWithSimpleString(ctx, "OK");
  73. return REDISMODULE_OK;
  74. }
  75. static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  76. if (argc != 4) {
  77. RedisModule_WrongArity(ctx);
  78. return REDISMODULE_OK;
  79. }
  80. long long encver;
  81. if (RedisModule_StringToLongLong(argv[3], &encver) != REDISMODULE_OK) {
  82. RedisModule_ReplyWithError(ctx, "Invalid integer value");
  83. return REDISMODULE_OK;
  84. }
  85. DataType *dt = RedisModule_LoadDataTypeFromStringEncver(argv[2], datatype, encver);
  86. if (!dt) {
  87. RedisModule_ReplyWithError(ctx, "Invalid data");
  88. return REDISMODULE_OK;
  89. }
  90. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  91. RedisModule_ModuleTypeSetValue(key, datatype, dt);
  92. RedisModule_CloseKey(key);
  93. RedisModule_ReplyWithLongLong(ctx, load_encver);
  94. return REDISMODULE_OK;
  95. }
  96. static int datatype_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  97. if (argc != 2) {
  98. RedisModule_WrongArity(ctx);
  99. return REDISMODULE_OK;
  100. }
  101. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ);
  102. DataType *dt = RedisModule_ModuleTypeGetValue(key);
  103. RedisModule_CloseKey(key);
  104. if (!dt) {
  105. RedisModule_ReplyWithNullArray(ctx);
  106. } else {
  107. RedisModule_ReplyWithArray(ctx, 2);
  108. RedisModule_ReplyWithLongLong(ctx, dt->intval);
  109. RedisModule_ReplyWithString(ctx, dt->strval);
  110. }
  111. return REDISMODULE_OK;
  112. }
  113. static int datatype_dump(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  114. if (argc != 2) {
  115. RedisModule_WrongArity(ctx);
  116. return REDISMODULE_OK;
  117. }
  118. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ);
  119. DataType *dt = RedisModule_ModuleTypeGetValue(key);
  120. RedisModule_CloseKey(key);
  121. RedisModuleString *reply = RedisModule_SaveDataTypeToString(ctx, dt, datatype);
  122. if (!reply) {
  123. RedisModule_ReplyWithError(ctx, "Failed to save");
  124. return REDISMODULE_OK;
  125. }
  126. RedisModule_ReplyWithString(ctx, reply);
  127. RedisModule_FreeString(ctx, reply);
  128. return REDISMODULE_OK;
  129. }
  130. static int datatype_swap(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  131. if (argc != 3) {
  132. RedisModule_WrongArity(ctx);
  133. return REDISMODULE_OK;
  134. }
  135. RedisModuleKey *a = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  136. RedisModuleKey *b = RedisModule_OpenKey(ctx, argv[2], REDISMODULE_WRITE);
  137. void *val = RedisModule_ModuleTypeGetValue(a);
  138. int error = (RedisModule_ModuleTypeReplaceValue(b, datatype, val, &val) == REDISMODULE_ERR ||
  139. RedisModule_ModuleTypeReplaceValue(a, datatype, val, NULL) == REDISMODULE_ERR);
  140. if (!error)
  141. RedisModule_ReplyWithSimpleString(ctx, "OK");
  142. else
  143. RedisModule_ReplyWithError(ctx, "ERR failed");
  144. RedisModule_CloseKey(a);
  145. RedisModule_CloseKey(b);
  146. return REDISMODULE_OK;
  147. }
  148. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  149. REDISMODULE_NOT_USED(argv);
  150. REDISMODULE_NOT_USED(argc);
  151. if (RedisModule_Init(ctx,"datatype",DATATYPE_ENC_VER,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
  152. return REDISMODULE_ERR;
  153. RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS);
  154. RedisModuleTypeMethods datatype_methods = {
  155. .version = REDISMODULE_TYPE_METHOD_VERSION,
  156. .rdb_load = datatype_load,
  157. .rdb_save = datatype_save,
  158. .free = datatype_free,
  159. .copy = datatype_copy
  160. };
  161. datatype = RedisModule_CreateDataType(ctx, "test___dt", 1, &datatype_methods);
  162. if (datatype == NULL)
  163. return REDISMODULE_ERR;
  164. if (RedisModule_CreateCommand(ctx,"datatype.set", datatype_set,"deny-oom",1,1,1) == REDISMODULE_ERR)
  165. return REDISMODULE_ERR;
  166. if (RedisModule_CreateCommand(ctx,"datatype.get", datatype_get,"",1,1,1) == REDISMODULE_ERR)
  167. return REDISMODULE_ERR;
  168. if (RedisModule_CreateCommand(ctx,"datatype.restore", datatype_restore,"deny-oom",1,1,1) == REDISMODULE_ERR)
  169. return REDISMODULE_ERR;
  170. if (RedisModule_CreateCommand(ctx,"datatype.dump", datatype_dump,"",1,1,1) == REDISMODULE_ERR)
  171. return REDISMODULE_ERR;
  172. if (RedisModule_CreateCommand(ctx,"datatype.swap", datatype_swap,"",1,1,1) == REDISMODULE_ERR)
  173. return REDISMODULE_ERR;
  174. return REDISMODULE_OK;
  175. }