testrdb.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "redismodule.h"
  2. #include <string.h>
  3. #include <assert.h>
  4. /* Module configuration, save aux or not? */
  5. long long conf_aux_count = 0;
  6. /* Registered type */
  7. RedisModuleType *testrdb_type = NULL;
  8. /* Global values to store and persist to aux */
  9. RedisModuleString *before_str = NULL;
  10. RedisModuleString *after_str = NULL;
  11. void replBackupCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data)
  12. {
  13. REDISMODULE_NOT_USED(e);
  14. REDISMODULE_NOT_USED(data);
  15. static RedisModuleString *before_str_backup = NULL;
  16. static RedisModuleString *after_str_backup = NULL;
  17. switch (sub) {
  18. case REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE:
  19. assert(before_str_backup == NULL);
  20. assert(after_str_backup == NULL);
  21. before_str_backup = before_str;
  22. after_str_backup = after_str;
  23. before_str = NULL;
  24. after_str = NULL;
  25. break;
  26. case REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE:
  27. if (before_str)
  28. RedisModule_FreeString(ctx, before_str);
  29. if (after_str)
  30. RedisModule_FreeString(ctx, after_str);
  31. before_str = before_str_backup;
  32. after_str = after_str_backup;
  33. before_str_backup = NULL;
  34. after_str_backup = NULL;
  35. break;
  36. case REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD:
  37. if (before_str_backup)
  38. RedisModule_FreeString(ctx, before_str_backup);
  39. if (after_str_backup)
  40. RedisModule_FreeString(ctx, after_str_backup);
  41. before_str_backup = NULL;
  42. after_str_backup = NULL;
  43. break;
  44. default:
  45. assert(0);
  46. }
  47. }
  48. void *testrdb_type_load(RedisModuleIO *rdb, int encver) {
  49. int count = RedisModule_LoadSigned(rdb);
  50. RedisModuleString *str = RedisModule_LoadString(rdb);
  51. float f = RedisModule_LoadFloat(rdb);
  52. long double ld = RedisModule_LoadLongDouble(rdb);
  53. if (RedisModule_IsIOError(rdb)) {
  54. RedisModuleCtx *ctx = RedisModule_GetContextFromIO(rdb);
  55. if (str)
  56. RedisModule_FreeString(ctx, str);
  57. return NULL;
  58. }
  59. /* Using the values only after checking for io errors. */
  60. assert(count==1);
  61. assert(encver==1);
  62. assert(f==1.5f);
  63. assert(ld==0.333333333333333333L);
  64. return str;
  65. }
  66. void testrdb_type_save(RedisModuleIO *rdb, void *value) {
  67. RedisModuleString *str = (RedisModuleString*)value;
  68. RedisModule_SaveSigned(rdb, 1);
  69. RedisModule_SaveString(rdb, str);
  70. RedisModule_SaveFloat(rdb, 1.5);
  71. RedisModule_SaveLongDouble(rdb, 0.333333333333333333L);
  72. }
  73. void testrdb_aux_save(RedisModuleIO *rdb, int when) {
  74. if (conf_aux_count==1) assert(when == REDISMODULE_AUX_AFTER_RDB);
  75. if (conf_aux_count==0) assert(0);
  76. if (when == REDISMODULE_AUX_BEFORE_RDB) {
  77. if (before_str) {
  78. RedisModule_SaveSigned(rdb, 1);
  79. RedisModule_SaveString(rdb, before_str);
  80. } else {
  81. RedisModule_SaveSigned(rdb, 0);
  82. }
  83. } else {
  84. if (after_str) {
  85. RedisModule_SaveSigned(rdb, 1);
  86. RedisModule_SaveString(rdb, after_str);
  87. } else {
  88. RedisModule_SaveSigned(rdb, 0);
  89. }
  90. }
  91. }
  92. int testrdb_aux_load(RedisModuleIO *rdb, int encver, int when) {
  93. assert(encver == 1);
  94. if (conf_aux_count==1) assert(when == REDISMODULE_AUX_AFTER_RDB);
  95. if (conf_aux_count==0) assert(0);
  96. RedisModuleCtx *ctx = RedisModule_GetContextFromIO(rdb);
  97. if (when == REDISMODULE_AUX_BEFORE_RDB) {
  98. if (before_str)
  99. RedisModule_FreeString(ctx, before_str);
  100. before_str = NULL;
  101. int count = RedisModule_LoadSigned(rdb);
  102. if (RedisModule_IsIOError(rdb))
  103. return REDISMODULE_ERR;
  104. if (count)
  105. before_str = RedisModule_LoadString(rdb);
  106. } else {
  107. if (after_str)
  108. RedisModule_FreeString(ctx, after_str);
  109. after_str = NULL;
  110. int count = RedisModule_LoadSigned(rdb);
  111. if (RedisModule_IsIOError(rdb))
  112. return REDISMODULE_ERR;
  113. if (count)
  114. after_str = RedisModule_LoadString(rdb);
  115. }
  116. if (RedisModule_IsIOError(rdb))
  117. return REDISMODULE_ERR;
  118. return REDISMODULE_OK;
  119. }
  120. void testrdb_type_free(void *value) {
  121. if (value)
  122. RedisModule_FreeString(NULL, (RedisModuleString*)value);
  123. }
  124. int testrdb_set_before(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  125. {
  126. if (argc != 2) {
  127. RedisModule_WrongArity(ctx);
  128. return REDISMODULE_OK;
  129. }
  130. if (before_str)
  131. RedisModule_FreeString(ctx, before_str);
  132. before_str = argv[1];
  133. RedisModule_RetainString(ctx, argv[1]);
  134. RedisModule_ReplyWithLongLong(ctx, 1);
  135. return REDISMODULE_OK;
  136. }
  137. int testrdb_get_before(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  138. {
  139. REDISMODULE_NOT_USED(argv);
  140. if (argc != 1){
  141. RedisModule_WrongArity(ctx);
  142. return REDISMODULE_OK;
  143. }
  144. if (before_str)
  145. RedisModule_ReplyWithString(ctx, before_str);
  146. else
  147. RedisModule_ReplyWithStringBuffer(ctx, "", 0);
  148. return REDISMODULE_OK;
  149. }
  150. int testrdb_set_after(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  151. {
  152. if (argc != 2){
  153. RedisModule_WrongArity(ctx);
  154. return REDISMODULE_OK;
  155. }
  156. if (after_str)
  157. RedisModule_FreeString(ctx, after_str);
  158. after_str = argv[1];
  159. RedisModule_RetainString(ctx, argv[1]);
  160. RedisModule_ReplyWithLongLong(ctx, 1);
  161. return REDISMODULE_OK;
  162. }
  163. int testrdb_get_after(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  164. {
  165. REDISMODULE_NOT_USED(argv);
  166. if (argc != 1){
  167. RedisModule_WrongArity(ctx);
  168. return REDISMODULE_OK;
  169. }
  170. if (after_str)
  171. RedisModule_ReplyWithString(ctx, after_str);
  172. else
  173. RedisModule_ReplyWithStringBuffer(ctx, "", 0);
  174. return REDISMODULE_OK;
  175. }
  176. int testrdb_set_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  177. {
  178. if (argc != 3){
  179. RedisModule_WrongArity(ctx);
  180. return REDISMODULE_OK;
  181. }
  182. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  183. RedisModuleString *str = RedisModule_ModuleTypeGetValue(key);
  184. if (str)
  185. RedisModule_FreeString(ctx, str);
  186. RedisModule_ModuleTypeSetValue(key, testrdb_type, argv[2]);
  187. RedisModule_RetainString(ctx, argv[2]);
  188. RedisModule_CloseKey(key);
  189. RedisModule_ReplyWithLongLong(ctx, 1);
  190. return REDISMODULE_OK;
  191. }
  192. int testrdb_get_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
  193. {
  194. if (argc != 2){
  195. RedisModule_WrongArity(ctx);
  196. return REDISMODULE_OK;
  197. }
  198. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  199. RedisModuleString *str = RedisModule_ModuleTypeGetValue(key);
  200. RedisModule_CloseKey(key);
  201. RedisModule_ReplyWithString(ctx, str);
  202. return REDISMODULE_OK;
  203. }
  204. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  205. REDISMODULE_NOT_USED(argv);
  206. REDISMODULE_NOT_USED(argc);
  207. if (RedisModule_Init(ctx,"testrdb",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
  208. return REDISMODULE_ERR;
  209. RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS);
  210. if (argc > 0)
  211. RedisModule_StringToLongLong(argv[0], &conf_aux_count);
  212. if (conf_aux_count==0) {
  213. RedisModuleTypeMethods datatype_methods = {
  214. .version = 1,
  215. .rdb_load = testrdb_type_load,
  216. .rdb_save = testrdb_type_save,
  217. .aof_rewrite = NULL,
  218. .digest = NULL,
  219. .free = testrdb_type_free,
  220. };
  221. testrdb_type = RedisModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods);
  222. if (testrdb_type == NULL)
  223. return REDISMODULE_ERR;
  224. } else {
  225. RedisModuleTypeMethods datatype_methods = {
  226. .version = REDISMODULE_TYPE_METHOD_VERSION,
  227. .rdb_load = testrdb_type_load,
  228. .rdb_save = testrdb_type_save,
  229. .aof_rewrite = NULL,
  230. .digest = NULL,
  231. .free = testrdb_type_free,
  232. .aux_load = testrdb_aux_load,
  233. .aux_save = testrdb_aux_save,
  234. .aux_save_triggers = (conf_aux_count == 1 ?
  235. REDISMODULE_AUX_AFTER_RDB :
  236. REDISMODULE_AUX_BEFORE_RDB | REDISMODULE_AUX_AFTER_RDB)
  237. };
  238. testrdb_type = RedisModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods);
  239. if (testrdb_type == NULL)
  240. return REDISMODULE_ERR;
  241. }
  242. if (RedisModule_CreateCommand(ctx,"testrdb.set.before", testrdb_set_before,"deny-oom",0,0,0) == REDISMODULE_ERR)
  243. return REDISMODULE_ERR;
  244. if (RedisModule_CreateCommand(ctx,"testrdb.get.before", testrdb_get_before,"",0,0,0) == REDISMODULE_ERR)
  245. return REDISMODULE_ERR;
  246. if (RedisModule_CreateCommand(ctx,"testrdb.set.after", testrdb_set_after,"deny-oom",0,0,0) == REDISMODULE_ERR)
  247. return REDISMODULE_ERR;
  248. if (RedisModule_CreateCommand(ctx,"testrdb.get.after", testrdb_get_after,"",0,0,0) == REDISMODULE_ERR)
  249. return REDISMODULE_ERR;
  250. if (RedisModule_CreateCommand(ctx,"testrdb.set.key", testrdb_set_key,"deny-oom",1,1,1) == REDISMODULE_ERR)
  251. return REDISMODULE_ERR;
  252. if (RedisModule_CreateCommand(ctx,"testrdb.get.key", testrdb_get_key,"",1,1,1) == REDISMODULE_ERR)
  253. return REDISMODULE_ERR;
  254. RedisModule_SubscribeToServerEvent(ctx,
  255. RedisModuleEvent_ReplBackup, replBackupCallback);
  256. return REDISMODULE_OK;
  257. }
  258. int RedisModule_OnUnload(RedisModuleCtx *ctx) {
  259. if (before_str)
  260. RedisModule_FreeString(ctx, before_str);
  261. if (after_str)
  262. RedisModule_FreeString(ctx, after_str);
  263. return REDISMODULE_OK;
  264. }