datatype2.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /* This module is used to test a use case of a module that stores information
  2. * about keys in global memory, and relies on the enhanced data type callbacks to
  3. * get key name and dbid on various operations.
  4. *
  5. * it simulates a simple memory allocator. The smallest allocation unit of
  6. * the allocator is a mem block with a size of 4KB. Multiple mem blocks are combined
  7. * using a linked list. These linked lists are placed in a global dict named 'mem_pool'.
  8. * Each db has a 'mem_pool'. You can use the 'mem.alloc' command to allocate a specified
  9. * number of mem blocks, and use 'mem.free' to release the memory. Use 'mem.write', 'mem.read'
  10. * to write and read the specified mem block (note that each mem block can only be written once).
  11. * Use 'mem.usage' to get the memory usage under different dbs, and it will return the size
  12. * mem blocks and used mem blocks under the db.
  13. * The specific structure diagram is as follows:
  14. *
  15. *
  16. * Global variables of the module:
  17. *
  18. * mem blocks link
  19. * ┌─────┬─────┐
  20. * │ │ │ ┌───┐ ┌───┐ ┌───┐
  21. * │ k1 │ ───┼───►│4KB├───►│4KB├───►│4KB│
  22. * │ │ │ └───┘ └───┘ └───┘
  23. * ├─────┼─────┤
  24. * ┌───────┐ ┌────► │ │ │ ┌───┐ ┌───┐
  25. * │ │ │ │ k2 │ ───┼───►│4KB├───►│4KB│
  26. * │ db0 ├──────┘ │ │ │ └───┘ └───┘
  27. * │ │ ├─────┼─────┤
  28. * ├───────┤ │ │ │ ┌───┐ ┌───┐ ┌───┐
  29. * │ │ │ k3 │ ───┼───►│4KB├───►│4KB├───►│4KB│
  30. * │ db1 ├──►null │ │ │ └───┘ └───┘ └───┘
  31. * │ │ └─────┴─────┘
  32. * ├───────┤ dict
  33. * │ │
  34. * │ db2 ├─────────┐
  35. * │ │ │
  36. * ├───────┤ │ ┌─────┬─────┐
  37. * │ │ │ │ │ │ ┌───┐ ┌───┐ ┌───┐
  38. * │ db3 ├──►null │ │ k1 │ ───┼───►│4KB├───►│4KB├───►│4KB│
  39. * │ │ │ │ │ │ └───┘ └───┘ └───┘
  40. * └───────┘ │ ├─────┼─────┤
  41. * mem_pool[MAX_DB] │ │ │ │ ┌───┐ ┌───┐
  42. * └──►│ k2 │ ───┼───►│4KB├───►│4KB│
  43. * │ │ │ └───┘ └───┘
  44. * └─────┴─────┘
  45. * dict
  46. *
  47. *
  48. * Keys in redis database:
  49. *
  50. * ┌───────┐
  51. * │ size │
  52. * ┌───────────►│ used │
  53. * │ │ mask │
  54. * ┌─────┬─────┐ │ └───────┘ ┌───────┐
  55. * │ │ │ │ MemAllocObject │ size │
  56. * │ k1 │ ───┼─┘ ┌───────────►│ used │
  57. * │ │ │ │ │ mask │
  58. * ├─────┼─────┤ ┌───────┐ ┌─────┬─────┐ │ └───────┘
  59. * │ │ │ │ size │ │ │ │ │ MemAllocObject
  60. * │ k2 │ ───┼─────────────►│ used │ │ k1 │ ───┼─┘
  61. * │ │ │ │ mask │ │ │ │
  62. * ├─────┼─────┤ └───────┘ ├─────┼─────┤
  63. * │ │ │ MemAllocObject │ │ │
  64. * │ k3 │ ───┼─┐ │ k2 │ ───┼─┐
  65. * │ │ │ │ │ │ │ │
  66. * └─────┴─────┘ │ ┌───────┐ └─────┴─────┘ │ ┌───────┐
  67. * redis db[0] │ │ size │ redis db[1] │ │ size │
  68. * └───────────►│ used │ └───────────►│ used │
  69. * │ mask │ │ mask │
  70. * └───────┘ └───────┘
  71. * MemAllocObject MemAllocObject
  72. *
  73. **/
  74. #include "redismodule.h"
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <ctype.h>
  78. #include <string.h>
  79. #include <stdint.h>
  80. static RedisModuleType *MemAllocType;
  81. #define MAX_DB 16
  82. RedisModuleDict *mem_pool[MAX_DB];
  83. typedef struct MemAllocObject {
  84. long long size;
  85. long long used;
  86. uint64_t mask;
  87. } MemAllocObject;
  88. MemAllocObject *createMemAllocObject(void) {
  89. MemAllocObject *o = RedisModule_Calloc(1, sizeof(*o));
  90. return o;
  91. }
  92. /*---------------------------- mem block apis ------------------------------------*/
  93. #define BLOCK_SIZE 4096
  94. struct MemBlock {
  95. char block[BLOCK_SIZE];
  96. struct MemBlock *next;
  97. };
  98. void MemBlockFree(struct MemBlock *head) {
  99. if (head) {
  100. struct MemBlock *block = head->next, *next;
  101. RedisModule_Free(head);
  102. while (block) {
  103. next = block->next;
  104. RedisModule_Free(block);
  105. block = next;
  106. }
  107. }
  108. }
  109. struct MemBlock *MemBlockCreate(long long num) {
  110. if (num <= 0) {
  111. return NULL;
  112. }
  113. struct MemBlock *head = RedisModule_Calloc(1, sizeof(struct MemBlock));
  114. struct MemBlock *block = head;
  115. while (--num) {
  116. block->next = RedisModule_Calloc(1, sizeof(struct MemBlock));
  117. block = block->next;
  118. }
  119. return head;
  120. }
  121. long long MemBlockNum(const struct MemBlock *head) {
  122. long long num = 0;
  123. const struct MemBlock *block = head;
  124. while (block) {
  125. num++;
  126. block = block->next;
  127. }
  128. return num;
  129. }
  130. size_t MemBlockWrite(struct MemBlock *head, long long block_index, const char *data, size_t size) {
  131. size_t w_size = 0;
  132. struct MemBlock *block = head;
  133. while (block_index-- && block) {
  134. block = block->next;
  135. }
  136. if (block) {
  137. size = size > BLOCK_SIZE ? BLOCK_SIZE:size;
  138. memcpy(block->block, data, size);
  139. w_size += size;
  140. }
  141. return w_size;
  142. }
  143. int MemBlockRead(struct MemBlock *head, long long block_index, char *data, size_t size) {
  144. size_t r_size = 0;
  145. struct MemBlock *block = head;
  146. while (block_index-- && block) {
  147. block = block->next;
  148. }
  149. if (block) {
  150. size = size > BLOCK_SIZE ? BLOCK_SIZE:size;
  151. memcpy(data, block->block, size);
  152. r_size += size;
  153. }
  154. return r_size;
  155. }
  156. void MemPoolFreeDb(RedisModuleCtx *ctx, int dbid) {
  157. RedisModuleString *key;
  158. void *tdata;
  159. RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0);
  160. while((key = RedisModule_DictNext(ctx, iter, &tdata)) != NULL) {
  161. MemBlockFree((struct MemBlock *)tdata);
  162. }
  163. RedisModule_DictIteratorStop(iter);
  164. RedisModule_FreeDict(NULL, mem_pool[dbid]);
  165. mem_pool[dbid] = RedisModule_CreateDict(NULL);
  166. }
  167. struct MemBlock *MemBlockClone(const struct MemBlock *head) {
  168. struct MemBlock *newhead = NULL;
  169. if (head) {
  170. newhead = RedisModule_Calloc(1, sizeof(struct MemBlock));
  171. memcpy(newhead->block, head->block, BLOCK_SIZE);
  172. struct MemBlock *newblock = newhead;
  173. const struct MemBlock *oldblock = head->next;
  174. while (oldblock) {
  175. newblock->next = RedisModule_Calloc(1, sizeof(struct MemBlock));
  176. newblock = newblock->next;
  177. memcpy(newblock->block, oldblock->block, BLOCK_SIZE);
  178. oldblock = oldblock->next;
  179. }
  180. }
  181. return newhead;
  182. }
  183. /*---------------------------- event handler ------------------------------------*/
  184. void swapDbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) {
  185. REDISMODULE_NOT_USED(ctx);
  186. REDISMODULE_NOT_USED(e);
  187. REDISMODULE_NOT_USED(sub);
  188. RedisModuleSwapDbInfo *ei = data;
  189. // swap
  190. RedisModuleDict *tmp = mem_pool[ei->dbnum_first];
  191. mem_pool[ei->dbnum_first] = mem_pool[ei->dbnum_second];
  192. mem_pool[ei->dbnum_second] = tmp;
  193. }
  194. void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) {
  195. REDISMODULE_NOT_USED(ctx);
  196. REDISMODULE_NOT_USED(e);
  197. int i;
  198. RedisModuleFlushInfo *fi = data;
  199. RedisModule_AutoMemory(ctx);
  200. if (sub == REDISMODULE_SUBEVENT_FLUSHDB_START) {
  201. if (fi->dbnum != -1) {
  202. MemPoolFreeDb(ctx, fi->dbnum);
  203. } else {
  204. for (i = 0; i < MAX_DB; i++) {
  205. MemPoolFreeDb(ctx, i);
  206. }
  207. }
  208. }
  209. }
  210. /*---------------------------- command implementation ------------------------------------*/
  211. /* MEM.ALLOC key block_num */
  212. int MemAlloc_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  213. RedisModule_AutoMemory(ctx);
  214. if (argc != 3) {
  215. return RedisModule_WrongArity(ctx);
  216. }
  217. long long block_num;
  218. if ((RedisModule_StringToLongLong(argv[2], &block_num) != REDISMODULE_OK) || block_num <= 0) {
  219. return RedisModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0");
  220. }
  221. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
  222. int type = RedisModule_KeyType(key);
  223. if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) {
  224. return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  225. }
  226. MemAllocObject *o;
  227. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  228. o = createMemAllocObject();
  229. RedisModule_ModuleTypeSetValue(key, MemAllocType, o);
  230. } else {
  231. o = RedisModule_ModuleTypeGetValue(key);
  232. }
  233. struct MemBlock *mem = MemBlockCreate(block_num);
  234. RedisModule_Assert(mem != NULL);
  235. RedisModule_DictSet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], mem);
  236. o->size = block_num;
  237. o->used = 0;
  238. o->mask = 0;
  239. RedisModule_ReplyWithLongLong(ctx, block_num);
  240. RedisModule_ReplicateVerbatim(ctx);
  241. return REDISMODULE_OK;
  242. }
  243. /* MEM.FREE key */
  244. int MemFree_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  245. RedisModule_AutoMemory(ctx);
  246. if (argc != 2) {
  247. return RedisModule_WrongArity(ctx);
  248. }
  249. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ);
  250. int type = RedisModule_KeyType(key);
  251. if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) {
  252. return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  253. }
  254. int ret = 0;
  255. MemAllocObject *o;
  256. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  257. RedisModule_ReplyWithLongLong(ctx, ret);
  258. return REDISMODULE_OK;
  259. } else {
  260. o = RedisModule_ModuleTypeGetValue(key);
  261. }
  262. int nokey;
  263. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey);
  264. if (!nokey && mem) {
  265. RedisModule_DictDel(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], NULL);
  266. MemBlockFree(mem);
  267. o->used = 0;
  268. o->size = 0;
  269. o->mask = 0;
  270. ret = 1;
  271. }
  272. RedisModule_ReplyWithLongLong(ctx, ret);
  273. RedisModule_ReplicateVerbatim(ctx);
  274. return REDISMODULE_OK;
  275. }
  276. /* MEM.WRITE key block_index data */
  277. int MemWrite_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  278. RedisModule_AutoMemory(ctx);
  279. if (argc != 4) {
  280. return RedisModule_WrongArity(ctx);
  281. }
  282. long long block_index;
  283. if ((RedisModule_StringToLongLong(argv[2], &block_index) != REDISMODULE_OK) || block_index < 0) {
  284. return RedisModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0");
  285. }
  286. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
  287. int type = RedisModule_KeyType(key);
  288. if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) {
  289. return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  290. }
  291. MemAllocObject *o;
  292. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  293. return RedisModule_ReplyWithError(ctx, "ERR Memory has not been allocated");
  294. } else {
  295. o = RedisModule_ModuleTypeGetValue(key);
  296. }
  297. if (o->mask & (1UL << block_index)) {
  298. return RedisModule_ReplyWithError(ctx, "ERR block is busy");
  299. }
  300. int ret = 0;
  301. int nokey;
  302. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey);
  303. if (!nokey && mem) {
  304. size_t len;
  305. const char *buf = RedisModule_StringPtrLen(argv[3], &len);
  306. ret = MemBlockWrite(mem, block_index, buf, len);
  307. o->mask |= (1UL << block_index);
  308. o->used++;
  309. }
  310. RedisModule_ReplyWithLongLong(ctx, ret);
  311. RedisModule_ReplicateVerbatim(ctx);
  312. return REDISMODULE_OK;
  313. }
  314. /* MEM.READ key block_index */
  315. int MemRead_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  316. RedisModule_AutoMemory(ctx);
  317. if (argc != 3) {
  318. return RedisModule_WrongArity(ctx);
  319. }
  320. long long block_index;
  321. if ((RedisModule_StringToLongLong(argv[2], &block_index) != REDISMODULE_OK) || block_index < 0) {
  322. return RedisModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0");
  323. }
  324. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ);
  325. int type = RedisModule_KeyType(key);
  326. if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) {
  327. return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  328. }
  329. MemAllocObject *o;
  330. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  331. return RedisModule_ReplyWithError(ctx, "ERR Memory has not been allocated");
  332. } else {
  333. o = RedisModule_ModuleTypeGetValue(key);
  334. }
  335. if (!(o->mask & (1UL << block_index))) {
  336. return RedisModule_ReplyWithNull(ctx);
  337. }
  338. int nokey;
  339. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey);
  340. RedisModule_Assert(nokey == 0 && mem != NULL);
  341. char buf[BLOCK_SIZE];
  342. MemBlockRead(mem, block_index, buf, sizeof(buf));
  343. /* Assuming that the contents are all c-style strings */
  344. RedisModule_ReplyWithStringBuffer(ctx, buf, strlen(buf));
  345. return REDISMODULE_OK;
  346. }
  347. /* MEM.USAGE dbid */
  348. int MemUsage_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  349. RedisModule_AutoMemory(ctx);
  350. if (argc != 2) {
  351. return RedisModule_WrongArity(ctx);
  352. }
  353. long long dbid;
  354. if ((RedisModule_StringToLongLong(argv[1], (long long *)&dbid) != REDISMODULE_OK)) {
  355. return RedisModule_ReplyWithError(ctx, "ERR invalid value: must be a integer");
  356. }
  357. if (dbid < 0 || dbid >= MAX_DB) {
  358. return RedisModule_ReplyWithError(ctx, "ERR dbid out of range");
  359. }
  360. long long size = 0, used = 0;
  361. void *data;
  362. RedisModuleString *key;
  363. RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0);
  364. while((key = RedisModule_DictNext(ctx, iter, &data)) != NULL) {
  365. int dbbackup = RedisModule_GetSelectedDb(ctx);
  366. RedisModule_SelectDb(ctx, dbid);
  367. RedisModuleKey *openkey = RedisModule_OpenKey(ctx, key, REDISMODULE_READ);
  368. int type = RedisModule_KeyType(openkey);
  369. RedisModule_Assert(type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(openkey) == MemAllocType);
  370. MemAllocObject *o = RedisModule_ModuleTypeGetValue(openkey);
  371. used += o->used;
  372. size += o->size;
  373. RedisModule_CloseKey(openkey);
  374. RedisModule_SelectDb(ctx, dbbackup);
  375. }
  376. RedisModule_DictIteratorStop(iter);
  377. RedisModule_ReplyWithArray(ctx, 4);
  378. RedisModule_ReplyWithSimpleString(ctx, "total");
  379. RedisModule_ReplyWithLongLong(ctx, size);
  380. RedisModule_ReplyWithSimpleString(ctx, "used");
  381. RedisModule_ReplyWithLongLong(ctx, used);
  382. return REDISMODULE_OK;
  383. }
  384. /* MEM.ALLOCANDWRITE key block_num block_index data block_index data ... */
  385. int MemAllocAndWrite_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  386. RedisModule_AutoMemory(ctx);
  387. if (argc < 3) {
  388. return RedisModule_WrongArity(ctx);
  389. }
  390. long long block_num;
  391. if ((RedisModule_StringToLongLong(argv[2], &block_num) != REDISMODULE_OK) || block_num <= 0) {
  392. return RedisModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0");
  393. }
  394. RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
  395. int type = RedisModule_KeyType(key);
  396. if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) {
  397. return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
  398. }
  399. MemAllocObject *o;
  400. if (type == REDISMODULE_KEYTYPE_EMPTY) {
  401. o = createMemAllocObject();
  402. RedisModule_ModuleTypeSetValue(key, MemAllocType, o);
  403. } else {
  404. o = RedisModule_ModuleTypeGetValue(key);
  405. }
  406. struct MemBlock *mem = MemBlockCreate(block_num);
  407. RedisModule_Assert(mem != NULL);
  408. RedisModule_DictSet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], mem);
  409. o->used = 0;
  410. o->mask = 0;
  411. o->size = block_num;
  412. int i = 3;
  413. long long block_index;
  414. for (; i < argc; i++) {
  415. /* Security is guaranteed internally, so no security check. */
  416. RedisModule_StringToLongLong(argv[i], &block_index);
  417. size_t len;
  418. const char * buf = RedisModule_StringPtrLen(argv[i + 1], &len);
  419. MemBlockWrite(mem, block_index, buf, len);
  420. o->used++;
  421. o->mask |= (1UL << block_index);
  422. }
  423. RedisModule_ReplyWithSimpleString(ctx, "OK");
  424. RedisModule_ReplicateVerbatim(ctx);
  425. return REDISMODULE_OK;
  426. }
  427. /*---------------------------- type callbacks ------------------------------------*/
  428. void *MemAllocRdbLoad(RedisModuleIO *rdb, int encver) {
  429. if (encver != 0) {
  430. return NULL;
  431. }
  432. MemAllocObject *o = createMemAllocObject();
  433. o->size = RedisModule_LoadSigned(rdb);
  434. o->used = RedisModule_LoadSigned(rdb);
  435. o->mask = RedisModule_LoadUnsigned(rdb);
  436. const RedisModuleString *key = RedisModule_GetKeyNameFromIO(rdb);
  437. int dbid = RedisModule_GetDbIdFromIO(rdb);
  438. if (o->size) {
  439. size_t size;
  440. char *tmpbuf;
  441. long long num = o->size;
  442. struct MemBlock *head = RedisModule_Calloc(1, sizeof(struct MemBlock));
  443. tmpbuf = RedisModule_LoadStringBuffer(rdb, &size);
  444. memcpy(head->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size);
  445. RedisModule_Free(tmpbuf);
  446. struct MemBlock *block = head;
  447. while (--num) {
  448. block->next = RedisModule_Calloc(1, sizeof(struct MemBlock));
  449. block = block->next;
  450. tmpbuf = RedisModule_LoadStringBuffer(rdb, &size);
  451. memcpy(block->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size);
  452. RedisModule_Free(tmpbuf);
  453. }
  454. RedisModule_DictSet(mem_pool[dbid], (RedisModuleString *)key, head);
  455. }
  456. return o;
  457. }
  458. void MemAllocRdbSave(RedisModuleIO *rdb, void *value) {
  459. MemAllocObject *o = value;
  460. RedisModule_SaveSigned(rdb, o->size);
  461. RedisModule_SaveSigned(rdb, o->used);
  462. RedisModule_SaveUnsigned(rdb, o->mask);
  463. const RedisModuleString *key = RedisModule_GetKeyNameFromIO(rdb);
  464. int dbid = RedisModule_GetDbIdFromIO(rdb);
  465. if (o->size) {
  466. int nokey;
  467. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey);
  468. RedisModule_Assert(nokey == 0 && mem != NULL);
  469. struct MemBlock *block = mem;
  470. while (block) {
  471. RedisModule_SaveStringBuffer(rdb, block->block, BLOCK_SIZE);
  472. block = block->next;
  473. }
  474. }
  475. }
  476. void MemAllocAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) {
  477. MemAllocObject *o = (MemAllocObject *)value;
  478. if (o->size) {
  479. int dbid = RedisModule_GetDbIdFromIO(aof);
  480. int nokey;
  481. size_t i = 0, j = 0;
  482. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey);
  483. RedisModule_Assert(nokey == 0 && mem != NULL);
  484. size_t array_size = o->size * 2;
  485. RedisModuleString ** string_array = RedisModule_Calloc(array_size, sizeof(RedisModuleString *));
  486. while (mem) {
  487. string_array[i] = RedisModule_CreateStringFromLongLong(NULL, j);
  488. string_array[i + 1] = RedisModule_CreateString(NULL, mem->block, BLOCK_SIZE);
  489. mem = mem->next;
  490. i += 2;
  491. j++;
  492. }
  493. RedisModule_EmitAOF(aof, "mem.allocandwrite", "slv", key, o->size, string_array, array_size);
  494. for (i = 0; i < array_size; i++) {
  495. RedisModule_FreeString(NULL, string_array[i]);
  496. }
  497. RedisModule_Free(string_array);
  498. } else {
  499. RedisModule_EmitAOF(aof, "mem.allocandwrite", "sl", key, o->size);
  500. }
  501. }
  502. void MemAllocFree(void *value) {
  503. RedisModule_Free(value);
  504. }
  505. void MemAllocUnlink(RedisModuleString *key, const void *value) {
  506. REDISMODULE_NOT_USED(key);
  507. REDISMODULE_NOT_USED(value);
  508. /* When unlink and unlink2 exist at the same time, we will only call unlink2. */
  509. RedisModule_Assert(0);
  510. }
  511. void MemAllocUnlink2(RedisModuleKeyOptCtx *ctx, const void *value) {
  512. MemAllocObject *o = (MemAllocObject *)value;
  513. const RedisModuleString *key = RedisModule_GetKeyNameFromOptCtx(ctx);
  514. int dbid = RedisModule_GetDbIdFromOptCtx(ctx);
  515. if (o->size) {
  516. void *oldval;
  517. RedisModule_DictDel(mem_pool[dbid], (RedisModuleString *)key, &oldval);
  518. RedisModule_Assert(oldval != NULL);
  519. MemBlockFree((struct MemBlock *)oldval);
  520. }
  521. }
  522. void MemAllocDigest(RedisModuleDigest *md, void *value) {
  523. MemAllocObject *o = (MemAllocObject *)value;
  524. RedisModule_DigestAddLongLong(md, o->size);
  525. RedisModule_DigestAddLongLong(md, o->used);
  526. RedisModule_DigestAddLongLong(md, o->mask);
  527. int dbid = RedisModule_GetDbIdFromDigest(md);
  528. const RedisModuleString *key = RedisModule_GetKeyNameFromDigest(md);
  529. if (o->size) {
  530. int nokey;
  531. struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey);
  532. RedisModule_Assert(nokey == 0 && mem != NULL);
  533. struct MemBlock *block = mem;
  534. while (block) {
  535. RedisModule_DigestAddStringBuffer(md, (unsigned char *)block->block, BLOCK_SIZE);
  536. block = block->next;
  537. }
  538. }
  539. }
  540. void *MemAllocCopy2(RedisModuleKeyOptCtx *ctx, const void *value) {
  541. const MemAllocObject *old = value;
  542. MemAllocObject *new = createMemAllocObject();
  543. new->size = old->size;
  544. new->used = old->used;
  545. new->mask = old->mask;
  546. int from_dbid = RedisModule_GetDbIdFromOptCtx(ctx);
  547. int to_dbid = RedisModule_GetToDbIdFromOptCtx(ctx);
  548. const RedisModuleString *fromkey = RedisModule_GetKeyNameFromOptCtx(ctx);
  549. const RedisModuleString *tokey = RedisModule_GetToKeyNameFromOptCtx(ctx);
  550. if (old->size) {
  551. int nokey;
  552. struct MemBlock *oldmem = (struct MemBlock *)RedisModule_DictGet(mem_pool[from_dbid], (RedisModuleString *)fromkey, &nokey);
  553. RedisModule_Assert(nokey == 0 && oldmem != NULL);
  554. struct MemBlock *newmem = MemBlockClone(oldmem);
  555. RedisModule_Assert(newmem != NULL);
  556. RedisModule_DictSet(mem_pool[to_dbid], (RedisModuleString *)tokey, newmem);
  557. }
  558. return new;
  559. }
  560. size_t MemAllocMemUsage2(RedisModuleKeyOptCtx *ctx, const void *value) {
  561. REDISMODULE_NOT_USED(ctx);
  562. uint64_t size = 0;
  563. MemAllocObject *o = (MemAllocObject *)value;
  564. size += sizeof(*o);
  565. size += o->size * sizeof(struct MemBlock);
  566. return size;
  567. }
  568. size_t MemAllocMemFreeEffort2(RedisModuleKeyOptCtx *ctx, const void *value) {
  569. REDISMODULE_NOT_USED(ctx);
  570. MemAllocObject *o = (MemAllocObject *)value;
  571. return o->size;
  572. }
  573. int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  574. REDISMODULE_NOT_USED(argv);
  575. REDISMODULE_NOT_USED(argc);
  576. if (RedisModule_Init(ctx, "datatype2", 1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
  577. return REDISMODULE_ERR;
  578. }
  579. RedisModuleTypeMethods tm = {
  580. .version = REDISMODULE_TYPE_METHOD_VERSION,
  581. .rdb_load = MemAllocRdbLoad,
  582. .rdb_save = MemAllocRdbSave,
  583. .aof_rewrite = MemAllocAofRewrite,
  584. .free = MemAllocFree,
  585. .digest = MemAllocDigest,
  586. .unlink = MemAllocUnlink,
  587. // .defrag = MemAllocDefrag, // Tested in defragtest.c
  588. .unlink2 = MemAllocUnlink2,
  589. .copy2 = MemAllocCopy2,
  590. .mem_usage2 = MemAllocMemUsage2,
  591. .free_effort2 = MemAllocMemFreeEffort2,
  592. };
  593. MemAllocType = RedisModule_CreateDataType(ctx, "mem_alloc", 0, &tm);
  594. if (MemAllocType == NULL) {
  595. return REDISMODULE_ERR;
  596. }
  597. if (RedisModule_CreateCommand(ctx, "mem.alloc", MemAlloc_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
  598. return REDISMODULE_ERR;
  599. }
  600. if (RedisModule_CreateCommand(ctx, "mem.free", MemFree_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
  601. return REDISMODULE_ERR;
  602. }
  603. if (RedisModule_CreateCommand(ctx, "mem.write", MemWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
  604. return REDISMODULE_ERR;
  605. }
  606. if (RedisModule_CreateCommand(ctx, "mem.read", MemRead_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) {
  607. return REDISMODULE_ERR;
  608. }
  609. if (RedisModule_CreateCommand(ctx, "mem.usage", MemUsage_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) {
  610. return REDISMODULE_ERR;
  611. }
  612. /* used for internal aof rewrite */
  613. if (RedisModule_CreateCommand(ctx, "mem.allocandwrite", MemAllocAndWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
  614. return REDISMODULE_ERR;
  615. }
  616. for(int i = 0; i < MAX_DB; i++){
  617. mem_pool[i] = RedisModule_CreateDict(NULL);
  618. }
  619. RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_FlushDB, flushdbCallback);
  620. RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_SwapDB, swapDbCallback);
  621. return REDISMODULE_OK;
  622. }