datatype.c 6.8 KB

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