Skip to content

Commit 47a9487

Browse files
committed
adding TCL
Signed-off-by: yairgott <[email protected]>
1 parent f9aad1a commit 47a9487

File tree

7 files changed

+109
-46
lines changed

7 files changed

+109
-46
lines changed

src/module.c

+13-10
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ static void zsetKeyReset(ValkeyModuleKey *key);
517517
static void moduleInitKeyTypeSpecific(ValkeyModuleKey *key);
518518
void VM_FreeDict(ValkeyModuleCtx *ctx, ValkeyModuleDict *d);
519519
void VM_FreeServerInfo(ValkeyModuleCtx *ctx, ValkeyModuleServerInfoData *data);
520-
void VM_ReleaseSharedSDS(ValkeyModuleSharedSDS *shared_sds);
520+
void VM_ReleaseSharedSDS(ValkeyModuleCtx *ctx, ValkeyModuleSharedSDS *shared_sds);
521521

522522
/* Helpers for VM_SetCommandInfo. */
523523
static int moduleValidateCommandInfo(const ValkeyModuleCommandInfo *info);
@@ -2685,7 +2685,7 @@ void autoMemoryCollect(ValkeyModuleCtx *ctx) {
26852685
case VALKEYMODULE_AM_KEY: VM_CloseKey(ptr); break;
26862686
case VALKEYMODULE_AM_DICT: VM_FreeDict(NULL, ptr); break;
26872687
case VALKEYMODULE_AM_INFO: VM_FreeServerInfo(NULL, ptr); break;
2688-
case VALKEYMODULE_AM_SHARED_SDS: VM_ReleaseSharedSDS(ptr); break;
2688+
case VALKEYMODULE_AM_SHARED_SDS: VM_ReleaseSharedSDS(NULL, ptr); break;
26892689
}
26902690
}
26912691
ctx->flags |= VALKEYMODULE_CTX_AUTO_MEMORY;
@@ -5462,9 +5462,9 @@ int VM_HashGet(ValkeyModuleKey *key, int flags, ...) {
54625462
if (key->value->encoding == OBJ_ENCODING_HASHTABLE) {
54635463
sds value_sds = hashTypeGetFromHashTable(key->value, field->ptr);
54645464
if (value_sds && sdsType(value_sds) == SDS_TYPE_32_SHARED) {
5465-
*valueptr = (ValkeyModuleSharedSDS *)(value_sds - sdsHdrSize(sdsType(value_sds)));
5465+
*valueptr = (ValkeyModuleSharedSDS *)sdsAllocPtr(value_sds);
54665466
sdsRetain(*valueptr);
5467-
autoMemoryAdd(key->ctx, VALKEYMODULE_AM_SHARED_SDS, *valueptr);
5467+
if (key->ctx != NULL) autoMemoryAdd(key->ctx, VALKEYMODULE_AM_SHARED_SDS, *valueptr);
54685468
}
54695469
}
54705470
} else {
@@ -13309,10 +13309,12 @@ ValkeyModuleScriptingEngineExecutionState VM_GetFunctionExecutionState(
1330913309
* Returns:
1331013310
* - A pointer to the created shared SDS object.
1331113311
*/
13312-
ValkeyModuleSharedSDS *VM_CreateSharedSDS(size_t len, ValkeyModuleSharedSDSAllocFunc allocfn, ValkeyModuleSharedSDSFreeCBFunc freecbfn) {
13312+
ValkeyModuleSharedSDS *VM_CreateSharedSDS(ValkeyModuleCtx *ctx, size_t len, ValkeyModuleSharedSDSAllocFunc allocfn, ValkeyModuleSharedSDSFreeCBFunc freecbfn) {
1331313313
size_t alloc;
13314-
void *buf = allocfn(len + sizeof(ValkeyModuleSharedSDS) + 1, &alloc);
13315-
return sdsInitShared((char *)buf, len, alloc, freecbfn);
13314+
void *buf = allocfn(len + offsetof(sdshdr32shared, buf) + 1, &alloc);
13315+
ValkeyModuleSharedSDS *shared_sds = sdsInitShared((char *)buf, len, alloc, freecbfn);
13316+
if (ctx != NULL) autoMemoryAdd(ctx, VALKEYMODULE_AM_SHARED_SDS, shared_sds);
13317+
return shared_sds;
1331613318
}
1331713319

1331813320
/* Retrieves the pointer to the shared SDS buffer along with its length.
@@ -13326,7 +13328,7 @@ ValkeyModuleSharedSDS *VM_CreateSharedSDS(size_t len, ValkeyModuleSharedSDSAlloc
1332613328
*/
1332713329
char *VM_SharedSDSPtrLen(ValkeyModuleSharedSDS *shared_sds, size_t *len) {
1332813330
*len = shared_sds->len;
13329-
return (char *)shared_sds + sizeof(ValkeyModuleSharedSDS);
13331+
return (char *)shared_sds + offsetof(sdshdr32shared, buf);
1333013332
}
1333113333

1333213334
/* Releases a shared SDS object by decrementing its intrusive reference count.
@@ -13337,8 +13339,9 @@ char *VM_SharedSDSPtrLen(ValkeyModuleSharedSDS *shared_sds, size_t *len) {
1333713339
* Parameters:
1333813340
* - `shared_sds`: A pointer to the `ValkeyModuleSharedSDS` object to be released.
1333913341
*/
13340-
void VM_ReleaseSharedSDS(ValkeyModuleSharedSDS *shared_sds) {
13341-
sdsfree(shared_sds->buf);
13342+
void VM_ReleaseSharedSDS(ValkeyModuleCtx *ctx, ValkeyModuleSharedSDS *shared_sds) {
13343+
int res = sdsReleaseShared(shared_sds);
13344+
if (ctx != NULL && res) autoMemoryFreed(ctx, VALKEYMODULE_AM_SHARED_SDS, shared_sds);
1334213345
}
1334313346

1334413347
/* MODULE command.

src/sds.c

+22-11
Original file line numberDiff line numberDiff line change
@@ -209,15 +209,22 @@ void sdsfree(sds s) {
209209
if (s == NULL) return;
210210
if (sdsType(s) == SDS_TYPE_32_SHARED) {
211211
SDS_HDR_VAR(32shared, s);
212-
if (atomic_fetch_sub_explicit(&sh->refcount, 1, memory_order_acq_rel) > 1) {
213-
return;
214-
}
215-
sh->freecbfn(sh, sdsAllocSize(s));
216-
s_free_with_size(s + sh->len + 1 - sdsAllocSize(s), sdsAllocSize(s));
212+
sdsReleaseShared(sh);
217213
return;
218214
}
219215
s_free_with_size(sdsAllocPtr(s), sdsAllocSize(s));
220216
}
217+
/* return 1 if the shared sds is freed otherwise 0 */
218+
int sdsReleaseShared(sdshdrshared *sh) {
219+
if (atomic_fetch_sub_explicit(&sh->refcount, 1, memory_order_acq_rel) > 1) {
220+
return 0;
221+
}
222+
char *ptr = sh->buf + sh->len + 1 - sdsAllocSize(sh->buf);
223+
size_t alloc_size = sdsAllocSize(sh->buf);
224+
sh->freecbfn(ptr, alloc_size);
225+
s_free_with_size(ptr, alloc_size);
226+
return 1;
227+
}
221228

222229
/* This variant of sdsfree() gets its argument as void, and is useful
223230
* as free method in data structures that expect a 'void free_object(void*)'
@@ -450,7 +457,11 @@ size_t sdsAllocSize(const_sds s) {
450457
/* Return the pointer of the actual SDS allocation (normally SDS strings
451458
* are referenced by the start of the string buffer). */
452459
void *sdsAllocPtr(const_sds s) {
453-
return (void *)(s - sdsHdrSize(sdsType(s)));
460+
char type = sdsType(s);
461+
if (type == SDS_TYPE_32_SHARED) {
462+
return (void *)(s - offsetof(sdshdrshared, buf));
463+
}
464+
return (void *)(s - sdsHdrSize(type));
454465
}
455466

456467
/* Initialize a shared sds into a buffer `buf`.
@@ -462,21 +473,21 @@ void *sdsAllocPtr(const_sds s) {
462473
* - `freecbfn`: A callback function that is invoked when the sds object is released.
463474
*
464475
* Returns:
465-
* - A pointer to the initialized `sdshdr32shared` structure.
476+
* - A pointer to the initialized `sdshdrshared` structure.
466477
*
467478
* Notes:
468479
* - The caller is responsible for ensuring that `buf` is large enough to accommodate
469480
* the SDS metadata, the string content, and the null terminator.
470481
* - The `freecbfn` does not directly free memory but is used primarily for
471482
* tracking deallocation events.
472483
*/
473-
sdshdr32shared *sdsInitShared(char *buf, size_t len, size_t alloc, sharedSdsFreeCB freecbfn) {
484+
sdshdrshared *sdsInitShared(char *buf, size_t len, size_t alloc, sharedSdsFreeCB freecbfn) {
474485
buf[alloc - 1] = 0;
475486
sds s = buf + alloc - len - 1;
476487
SDS_HDR_VAR(32shared, s);
477488
sh->freecbfn = freecbfn;
478489
atomic_init(&sh->refcount, 1);
479-
sh->len = len;
490+
sh->len = (uint32_t)len;
480491
sh->alloc = alloc - sdsHdrSize(SDS_TYPE_32_SHARED) - 1;
481492
sh->flags = SDS_TYPE_32_SHARED;
482493
return sh;
@@ -485,10 +496,10 @@ sdshdr32shared *sdsInitShared(char *buf, size_t len, size_t alloc, sharedSdsFree
485496
/* Increases the reference count of a shared SDS object.
486497
*
487498
* Parameters:
488-
* - `sh`: A pointer to the `sdshdr32shared` structure whose reference count
499+
* - `sh`: A pointer to the `sdshdrshared` structure whose reference count
489500
* should be increased.
490501
*/
491-
void sdsRetain(sdshdr32shared *sh) {
502+
void sdsRetain(sdshdrshared *sh) {
492503
atomic_fetch_add_explicit(&sh->refcount, 1, memory_order_relaxed);
493504
}
494505
/* Increment the sds length and decrements the left free space at the

src/sds.h

+8-7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern const char *SDS_NOINIT;
3939
#include <stdarg.h>
4040
#include <stdint.h>
4141
#include <stdatomic.h>
42+
#include <stddef.h>
4243

4344
/* Constness:
4445
*
@@ -82,7 +83,7 @@ typedef struct __attribute__((__packed__)) sdshdr32shared {
8283
uint32_t alloc; /* excluding the header and null terminator */
8384
unsigned char flags; /* 3 lsb of type, 5 unused bits */
8485
char buf[];
85-
} sdshdr32shared;
86+
} sdshdrshared;
8687
struct __attribute__((__packed__)) sdshdr64 {
8788
uint64_t len; /* used */
8889
uint64_t alloc; /* excluding the header and null terminator */
@@ -98,8 +99,8 @@ struct __attribute__((__packed__)) sdshdr64 {
9899
#define SDS_TYPE_32_SHARED 5
99100
#define SDS_TYPE_MASK 7
100101
#define SDS_TYPE_BITS 3
101-
#define SDS_HDR_VAR(T, s) struct sdshdr##T *sh = (void *)((s) - (sizeof(struct sdshdr##T)));
102-
#define SDS_HDR(T, s) ((struct sdshdr##T *)((s) - (sizeof(struct sdshdr##T))))
102+
#define SDS_HDR_VAR(T, s) struct sdshdr##T *sh = (void *)((s) - (offsetof(struct sdshdr##T, buf)));
103+
#define SDS_HDR(T, s) ((struct sdshdr##T *)((s) - (offsetof(struct sdshdr##T, buf))))
103104
#define SDS_TYPE_5_LEN(f) ((unsigned char)(f) >> SDS_TYPE_BITS)
104105

105106
static inline unsigned char sdsType(const_sds s) {
@@ -164,8 +165,7 @@ static inline size_t sdsavail(const_sds s) {
164165
return sh->alloc - sh->len;
165166
}
166167
case SDS_TYPE_32_SHARED: {
167-
SDS_HDR_VAR(32shared, s);
168-
return sh->alloc - sh->len;
168+
return 0;
169169
}
170170
}
171171
return 0;
@@ -289,8 +289,9 @@ sds sdsRemoveFreeSpace(sds s, int would_regrow);
289289
sds sdsResize(sds s, size_t size, int would_regrow);
290290
size_t sdsAllocSize(const_sds s);
291291
void *sdsAllocPtr(const_sds s);
292-
sdshdr32shared *sdsInitShared(char *buf, size_t len, size_t alloc, sharedSdsFreeCB freecbfn);
293-
void sdsRetain(sdshdr32shared *sh);
292+
sdshdrshared *sdsInitShared(char *buf, size_t len, size_t alloc, sharedSdsFreeCB freecbfn);
293+
void sdsRetain(sdshdrshared *sh);
294+
int sdsReleaseShared(sdshdrshared *sh);
294295

295296
/* Returns the minimum required size to store an sds string of the given length
296297
* and type. */

src/t_zset.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -4235,7 +4235,7 @@ void zrandmemberWithCountCommand(client *c, long l, int withscores) {
42354235

42364236
while (added < count) {
42374237
listpackEntry key;
4238-
double score;
4238+
double score = 0;
42394239
zsetTypeRandomElement(zsetobj, size, &key, withscores ? &score : NULL);
42404240

42414241
/* Try to add the object to the dictionary. If it already exists

src/valkeymodule.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1888,11 +1888,11 @@ VALKEYMODULE_API int (*ValkeyModule_UnregisterScriptingEngine)(ValkeyModuleCtx *
18881888
const char *engine_name) VALKEYMODULE_ATTR;
18891889

18901890
VALKEYMODULE_API ValkeyModuleScriptingEngineExecutionState (*ValkeyModule_GetFunctionExecutionState)(ValkeyModuleScriptingEngineServerRuntimeCtx *server_ctx) VALKEYMODULE_ATTR;
1891-
VALKEYMODULE_API ValkeyModuleSharedSDS *(*ValkeyModule_CreateSharedSDS)(size_t len,
1891+
VALKEYMODULE_API ValkeyModuleSharedSDS *(*ValkeyModule_CreateSharedSDS)(ValkeyModuleCtx *ctx, size_t len,
18921892
ValkeyModuleSharedSDSAllocFunc allocfn,
18931893
ValkeyModuleSharedSDSFreeCBFunc freecbfn) VALKEYMODULE_ATTR;
18941894
VALKEYMODULE_API char *(*ValkeyModule_SharedSDSPtrLen)(ValkeyModuleSharedSDS *shared_sds, size_t *len) VALKEYMODULE_ATTR;
1895-
VALKEYMODULE_API void (*ValkeyModule_ReleaseSharedSDS)(ValkeyModuleSharedSDS *shared_sds) VALKEYMODULE_ATTR;
1895+
VALKEYMODULE_API void (*ValkeyModule_ReleaseSharedSDS)(ValkeyModuleCtx *ctx, ValkeyModuleSharedSDS *shared_sds) VALKEYMODULE_ATTR;
18961896

18971897
#define ValkeyModule_IsAOFClient(id) ((id) == UINT64_MAX)
18981898

tests/modules/hash.c

+56-14
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,52 @@
22
#include <strings.h>
33
#include <errno.h>
44
#include <stdlib.h>
5+
#include <string.h>
6+
7+
#define UNUSED(V) ((void) V)
8+
9+
int shared_sds_cnt = 0;
10+
ValkeyModuleSharedSDS *shared_sds_arr[4];
11+
12+
void *shared_sds_alloc(size_t len, size_t *alloc) {
13+
*alloc = 2 * len;
14+
return malloc(*alloc * sizeof(char));
15+
}
16+
17+
void shared_sds_free_cb(void *ptr, size_t size) {
18+
UNUSED(size);
19+
UNUSED(ptr);
20+
}
21+
22+
void check_hash_get_shared_sds(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int result) {
23+
if (result == 0) return;
24+
ValkeyModuleKey *key = ValkeyModule_OpenKey(ctx, argv[1], VALKEYMODULE_READ);
25+
for (int i = 0; i < shared_sds_cnt; ++i) {
26+
ValkeyModuleSharedSDS *get_value = NULL;
27+
ValkeyModule_HashGet(key, VALKEYMODULE_HASH_SHAREBLE_VALUES,
28+
argv[i*2 + 3], &get_value, NULL);
29+
if (get_value) {
30+
ValkeyModule_Assert(shared_sds_arr[i] == get_value);
31+
}
32+
}
33+
}
534

635
/* If a string is ":deleted:", the special value for deleted hash fields is
736
* returned; otherwise the input string is returned. */
8-
static ValkeyModuleString *value_or_delete(ValkeyModuleString *s) {
9-
if (!strcasecmp(ValkeyModule_StringPtrLen(s, NULL), ":delete:"))
37+
static void *value_or_delete(ValkeyModuleCtx *ctx, ValkeyModuleString *s, int flags) {
38+
size_t str_len;
39+
const char *str = ValkeyModule_StringPtrLen(s, &str_len);
40+
if (flags & VALKEYMODULE_HASH_SHAREBLE_VALUES) {
41+
ValkeyModuleSharedSDS *shared_sds = ValkeyModule_CreateSharedSDS(ctx, str_len, shared_sds_alloc, shared_sds_free_cb);
42+
size_t sds_len;
43+
char *sds_str = ValkeyModule_SharedSDSPtrLen(shared_sds, &sds_len);
44+
ValkeyModule_Assert(sds_len == str_len);
45+
memcpy(sds_str, str, str_len);
46+
shared_sds_arr[shared_sds_cnt++] = shared_sds;
47+
return shared_sds;
48+
}
49+
shared_sds_arr[shared_sds_cnt++] = NULL;
50+
if (!strcasecmp(str, ":delete:"))
1051
return VALKEYMODULE_HASH_DELETE;
1152
else
1253
return s;
@@ -22,6 +63,7 @@ int hash_set(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
2263
if (argc < 5 || argc % 2 == 0 || argc > 11)
2364
return ValkeyModule_WrongArity(ctx);
2465

66+
shared_sds_cnt = 0;
2567
ValkeyModule_AutoMemory(ctx);
2668
ValkeyModuleKey *key = ValkeyModule_OpenKey(ctx, argv[1], VALKEYMODULE_WRITE);
2769

@@ -33,6 +75,7 @@ int hash_set(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
3375
case 'n': flags |= VALKEYMODULE_HASH_NX; break;
3476
case 'x': flags |= VALKEYMODULE_HASH_XX; break;
3577
case 'a': flags |= VALKEYMODULE_HASH_COUNT_ALL; break;
78+
case 's': flags |= VALKEYMODULE_HASH_SHAREBLE_VALUES; break;
3679
}
3780
}
3881

@@ -41,38 +84,37 @@ int hash_set(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
4184
errno = 0;
4285
if (argc == 5) {
4386
result = ValkeyModule_HashSet(key, flags,
44-
argv[3], value_or_delete(argv[4]),
87+
argv[3], value_or_delete(ctx, argv[4], flags),
4588
NULL);
4689
} else if (argc == 7) {
4790
result = ValkeyModule_HashSet(key, flags,
48-
argv[3], value_or_delete(argv[4]),
49-
argv[5], value_or_delete(argv[6]),
91+
argv[3], value_or_delete(ctx, argv[4], flags),
92+
argv[5], value_or_delete(ctx, argv[6], flags),
5093
NULL);
5194
} else if (argc == 9) {
5295
result = ValkeyModule_HashSet(key, flags,
53-
argv[3], value_or_delete(argv[4]),
54-
argv[5], value_or_delete(argv[6]),
55-
argv[7], value_or_delete(argv[8]),
96+
argv[3], value_or_delete(ctx, argv[4], flags),
97+
argv[5], value_or_delete(ctx, argv[6], flags),
98+
argv[7], value_or_delete(ctx, argv[8], flags),
5699
NULL);
57100
} else if (argc == 11) {
58101
result = ValkeyModule_HashSet(key, flags,
59-
argv[3], value_or_delete(argv[4]),
60-
argv[5], value_or_delete(argv[6]),
61-
argv[7], value_or_delete(argv[8]),
62-
argv[9], value_or_delete(argv[10]),
102+
argv[3], value_or_delete(ctx, argv[4], flags),
103+
argv[5], value_or_delete(ctx, argv[6], flags),
104+
argv[7], value_or_delete(ctx, argv[8], flags),
105+
argv[9], value_or_delete(ctx, argv[10], flags),
63106
NULL);
64107
} else {
65108
return ValkeyModule_ReplyWithError(ctx, "ERR too many fields");
66109
}
67-
68110
/* Check errno */
69111
if (result == 0) {
70112
if (errno == ENOTSUP)
71113
return ValkeyModule_ReplyWithError(ctx, VALKEYMODULE_ERRORMSG_WRONGTYPE);
72114
else
73115
ValkeyModule_Assert(errno == ENOENT);
74116
}
75-
117+
check_hash_get_shared_sds(ctx, argv, result);
76118
return ValkeyModule_ReplyWithLongLong(ctx, result);
77119
}
78120

tests/unit/moduleapi/hash.tcl

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ start_server {tags {"modules"}} {
1818
assert_equal 0 [r hash.set k "xa" new stuff not inserted]
1919
assert_equal 1 [r hash.set k "x" squirrel ofcourse]
2020
assert_equal 1 [r hash.set k "" sushi :delete: none :delete:]
21+
assert_equal 1 [r hash.set k "nas" carrot orange]
22+
assert_equal 0 [r hash.set k "nas" carrot pink]
23+
assert_equal 1 [r hash.set k "a" apple red]
24+
assert_equal 1 [r hash.set k "xs" apple green]
25+
assert_equal 1 [r hash.set k "sa" tomato red]
26+
assert_equal 1 [r hash.set k "" tomato :delete:]
2127
r hgetall k
22-
} {squirrel ofcourse banana no what nothing something nice}
28+
} {squirrel ofcourse banana no what nothing something nice carrot orange apple green}
2329

2430
test "Unload the module - hash" {
2531
assert_equal {OK} [r module unload hash]

0 commit comments

Comments
 (0)