test_lazyfree.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* This module emulates a linked list for lazyfree testing of modules, which
  2. is a simplified version of 'hellotype.c'
  3. */
  4. #include "redismodule.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <string.h>
  9. #include <stdint.h>
  10. static RedisModuleType *LazyFreeLinkType;
  11. struct LazyFreeLinkNode {
  12. int64_t value;
  13. struct LazyFreeLinkNode *next;
  14. };
  15. struct LazyFreeLinkObject {
  16. struct LazyFreeLinkNode *head;
  17. size_t len; /* Number of elements added. */
  18. };
  19. struct LazyFreeLinkObject *createLazyFreeLinkObject(void) {
  20. struct LazyFreeLinkObject *o;
  21. o = RedisModule_Alloc(sizeof(*o));
  22. o->head = NULL;
  23. o->len = 0;
  24. return o;
  25. }
  26. void LazyFreeLinkInsert(struct LazyFreeLinkObject *o, int64_t ele) {
  27. struct LazyFreeLinkNode *next = o->head, *newnode, *prev = NULL;
  28. while(next && next->value < ele) {
  29. prev = next;
  30. next = next->next;
  31. }
  32. newnode = RedisModule_Alloc(sizeof(*newnode));
  33. newnode->value = ele;
  34. newnode->next = next;
  35. if (prev) {
  36. prev->next = newnode;
  37. } else {
  38. o->head = newnode;
  39. }
  40. o->len++;
  41. }
  42. void LazyFreeLinkReleaseObject(struct LazyFreeLinkObject *o) {
  43. struct LazyFreeLinkNode *cur, *next;
  44. cur = o->head;
  45. while(cur) {
  46. next = cur->next;
  47. RedisModule_Free(cur);
  48. cur = next;
  49. }
  50. RedisModule_Free(o);
  51. }
  52. /* LAZYFREELINK.INSERT key value */
  53. int LazyFreeLinkInsert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  54. RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
  55. if (argc != 3) return RedisModule_WrongArity(ctx);
  56. RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
  57. REDISMODULE_READ|REDISMODULE_WRITE);
  58. int type = RedisModule_KeyType(key);
  59. if (type != REDISMODULE_KEYTYPE_EMPTY &&
  60. RedisModule_ModuleTypeGetType(key) != LazyFreeLinkType)
  61. {
  62. return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
  63. }
  64. long long value;
  65. if ((RedisModule_StringToLongLong(argv[2],&value) != REDISMODULE_OK)) {
  66. return RedisModule_ReplyWithError(ctx,"ERR invalid value: must be a signed 64 bit integer");
  67. }
  68. struct LazyFreeLinkObject *hto;
  69. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  70. hto = createLazyFreeLinkObject();
  71. RedisModule_ModuleTypeSetValue(key,LazyFreeLinkType,hto);
  72. } else {
  73. hto = RedisModule_ModuleTypeGetValue(key);
  74. }
  75. LazyFreeLinkInsert(hto,value);
  76. RedisModule_SignalKeyAsReady(ctx,argv[1]);
  77. RedisModule_ReplyWithLongLong(ctx,hto->len);
  78. RedisModule_ReplicateVerbatim(ctx);
  79. return REDISMODULE_OK;
  80. }
  81. /* LAZYFREELINK.LEN key */
  82. int LazyFreeLinkLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  83. RedisModule_AutoMemory(ctx); /* Use automatic memory management. */
  84. if (argc != 2) return RedisModule_WrongArity(ctx);
  85. RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
  86. REDISMODULE_READ|REDISMODULE_WRITE);
  87. int type = RedisModule_KeyType(key);
  88. if (type != REDISMODULE_KEYTYPE_EMPTY &&
  89. RedisModule_ModuleTypeGetType(key) != LazyFreeLinkType)
  90. {
  91. return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
  92. }
  93. struct LazyFreeLinkObject *hto = RedisModule_ModuleTypeGetValue(key);
  94. RedisModule_ReplyWithLongLong(ctx,hto ? hto->len : 0);
  95. return REDISMODULE_OK;
  96. }
  97. void *LazyFreeLinkRdbLoad(RedisModuleIO *rdb, int encver) {
  98. if (encver != 0) {
  99. return NULL;
  100. }
  101. uint64_t elements = RedisModule_LoadUnsigned(rdb);
  102. struct LazyFreeLinkObject *hto = createLazyFreeLinkObject();
  103. while(elements--) {
  104. int64_t ele = RedisModule_LoadSigned(rdb);
  105. LazyFreeLinkInsert(hto,ele);
  106. }
  107. return hto;
  108. }
  109. void LazyFreeLinkRdbSave(RedisModuleIO *rdb, void *value) {
  110. struct LazyFreeLinkObject *hto = value;
  111. struct LazyFreeLinkNode *node = hto->head;
  112. RedisModule_SaveUnsigned(rdb,hto->len);
  113. while(node) {
  114. RedisModule_SaveSigned(rdb,node->value);
  115. node = node->next;
  116. }
  117. }
  118. void LazyFreeLinkAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) {
  119. struct LazyFreeLinkObject *hto = value;
  120. struct LazyFreeLinkNode *node = hto->head;
  121. while(node) {
  122. RedisModule_EmitAOF(aof,"LAZYFREELINK.INSERT","sl",key,node->value);
  123. node = node->next;
  124. }
  125. }
  126. void LazyFreeLinkFree(void *value) {
  127. LazyFreeLinkReleaseObject(value);
  128. }
  129. size_t LazyFreeLinkFreeEffort(RedisModuleString *key, const void *value) {
  130. REDISMODULE_NOT_USED(key);
  131. const struct LazyFreeLinkObject *hto = value;
  132. return hto->len;
  133. }
  134. void LazyFreeLinkUnlink(RedisModuleString *key, const void *value) {
  135. REDISMODULE_NOT_USED(key);
  136. REDISMODULE_NOT_USED(value);
  137. /* Here you can know which key and value is about to be freed. */
  138. }
  139. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  140. REDISMODULE_NOT_USED(argv);
  141. REDISMODULE_NOT_USED(argc);
  142. if (RedisModule_Init(ctx,"lazyfreetest",1,REDISMODULE_APIVER_1)
  143. == REDISMODULE_ERR) return REDISMODULE_ERR;
  144. /* We only allow our module to be loaded when the redis core version is greater than the version of my module */
  145. if (RedisModule_GetTypeMethodVersion() < REDISMODULE_TYPE_METHOD_VERSION) {
  146. return REDISMODULE_ERR;
  147. }
  148. RedisModuleTypeMethods tm = {
  149. .version = REDISMODULE_TYPE_METHOD_VERSION,
  150. .rdb_load = LazyFreeLinkRdbLoad,
  151. .rdb_save = LazyFreeLinkRdbSave,
  152. .aof_rewrite = LazyFreeLinkAofRewrite,
  153. .free = LazyFreeLinkFree,
  154. .free_effort = LazyFreeLinkFreeEffort,
  155. .unlink = LazyFreeLinkUnlink,
  156. };
  157. LazyFreeLinkType = RedisModule_CreateDataType(ctx,"test_lazy",0,&tm);
  158. if (LazyFreeLinkType == NULL) return REDISMODULE_ERR;
  159. if (RedisModule_CreateCommand(ctx,"lazyfreelink.insert",
  160. LazyFreeLinkInsert_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR)
  161. return REDISMODULE_ERR;
  162. if (RedisModule_CreateCommand(ctx,"lazyfreelink.len",
  163. LazyFreeLinkLen_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR)
  164. return REDISMODULE_ERR;
  165. return REDISMODULE_OK;
  166. }