forked from redis/redis
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ModuleDataType to/from string serialization.
Add two new functions that leverage the RedisModuleDataType mechanism for RDB serialization/deserialization and make it possible to use it to/from arbitrary strings: * RM_SaveDataTypeToString() * RM_LoadDataTypeFromString()
- Loading branch information
Showing
6 changed files
with
250 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* This module current tests a small subset but should be extended in the future | ||
* for general ModuleDataType coverage. | ||
*/ | ||
|
||
#include "redismodule.h" | ||
|
||
static RedisModuleType *datatype = NULL; | ||
|
||
typedef struct { | ||
long long intval; | ||
RedisModuleString *strval; | ||
} DataType; | ||
|
||
static void *datatype_load(RedisModuleIO *io, int encver) { | ||
(void) encver; | ||
|
||
int intval = RedisModule_LoadSigned(io); | ||
if (RedisModule_IsIOError(io)) return NULL; | ||
|
||
RedisModuleString *strval = RedisModule_LoadString(io); | ||
if (RedisModule_IsIOError(io)) return NULL; | ||
|
||
DataType *dt = (DataType *) RedisModule_Alloc(sizeof(DataType)); | ||
dt->intval = intval; | ||
dt->strval = strval; | ||
return dt; | ||
} | ||
|
||
static void datatype_save(RedisModuleIO *io, void *value) { | ||
DataType *dt = (DataType *) value; | ||
RedisModule_SaveSigned(io, dt->intval); | ||
RedisModule_SaveString(io, dt->strval); | ||
} | ||
|
||
static void datatype_free(void *value) { | ||
if (value) { | ||
DataType *dt = (DataType *) value; | ||
|
||
if (dt->strval) RedisModule_FreeString(NULL, dt->strval); | ||
RedisModule_Free(dt); | ||
} | ||
} | ||
|
||
static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | ||
if (argc != 4) { | ||
RedisModule_WrongArity(ctx); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
long long intval; | ||
|
||
if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) { | ||
RedisModule_ReplyWithError(ctx, "Invalid integr value"); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); | ||
DataType *dt = RedisModule_Calloc(sizeof(DataType), 1); | ||
dt->intval = intval; | ||
dt->strval = argv[3]; | ||
RedisModule_RetainString(ctx, dt->strval); | ||
|
||
RedisModule_ModuleTypeSetValue(key, datatype, dt); | ||
RedisModule_CloseKey(key); | ||
RedisModule_ReplyWithSimpleString(ctx, "OK"); | ||
|
||
return REDISMODULE_OK; | ||
} | ||
|
||
static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | ||
if (argc != 3) { | ||
RedisModule_WrongArity(ctx); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
DataType *dt = RedisModule_LoadDataTypeFromString(argv[2], datatype); | ||
if (!dt) { | ||
RedisModule_ReplyWithError(ctx, "Invalid data"); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); | ||
RedisModule_ModuleTypeSetValue(key, datatype, dt); | ||
RedisModule_CloseKey(key); | ||
RedisModule_ReplyWithSimpleString(ctx, "OK"); | ||
|
||
return REDISMODULE_OK; | ||
} | ||
|
||
static int datatype_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | ||
if (argc != 2) { | ||
RedisModule_WrongArity(ctx); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); | ||
DataType *dt = RedisModule_ModuleTypeGetValue(key); | ||
RedisModule_CloseKey(key); | ||
|
||
RedisModule_ReplyWithArray(ctx, 2); | ||
RedisModule_ReplyWithLongLong(ctx, dt->intval); | ||
RedisModule_ReplyWithString(ctx, dt->strval); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
static int datatype_dump(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | ||
if (argc != 2) { | ||
RedisModule_WrongArity(ctx); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); | ||
DataType *dt = RedisModule_ModuleTypeGetValue(key); | ||
RedisModule_CloseKey(key); | ||
|
||
RedisModuleString *reply = RedisModule_SaveDataTypeToString(ctx, dt, datatype); | ||
if (!reply) { | ||
RedisModule_ReplyWithError(ctx, "Failed to save"); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
RedisModule_ReplyWithString(ctx, reply); | ||
RedisModule_FreeString(ctx, reply); | ||
return REDISMODULE_OK; | ||
} | ||
|
||
|
||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | ||
REDISMODULE_NOT_USED(argv); | ||
REDISMODULE_NOT_USED(argc); | ||
|
||
if (RedisModule_Init(ctx,"datatype",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) | ||
return REDISMODULE_ERR; | ||
|
||
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS); | ||
|
||
RedisModuleTypeMethods datatype_methods = { | ||
.version = REDISMODULE_TYPE_METHOD_VERSION, | ||
.rdb_load = datatype_load, | ||
.rdb_save = datatype_save, | ||
.free = datatype_free, | ||
}; | ||
|
||
datatype = RedisModule_CreateDataType(ctx, "test___dt", 1, &datatype_methods); | ||
if (datatype == NULL) | ||
return REDISMODULE_ERR; | ||
|
||
if (RedisModule_CreateCommand(ctx,"datatype.set", datatype_set,"deny-oom",1,1,1) == REDISMODULE_ERR) | ||
return REDISMODULE_ERR; | ||
|
||
if (RedisModule_CreateCommand(ctx,"datatype.get", datatype_get,"",1,1,1) == REDISMODULE_ERR) | ||
return REDISMODULE_ERR; | ||
|
||
if (RedisModule_CreateCommand(ctx,"datatype.restore", datatype_restore,"deny-oom",1,1,1) == REDISMODULE_ERR) | ||
return REDISMODULE_ERR; | ||
|
||
if (RedisModule_CreateCommand(ctx,"datatype.dump", datatype_dump,"",1,1,1) == REDISMODULE_ERR) | ||
return REDISMODULE_ERR; | ||
|
||
return REDISMODULE_OK; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
set testmodule [file normalize tests/modules/datatype.so] | ||
|
||
start_server {tags {"modules"}} { | ||
r module load $testmodule | ||
|
||
test {DataType: Test module is sane, GET/SET work.} { | ||
r datatype.set dtkey 100 stringval | ||
assert {[r datatype.get dtkey] eq {100 stringval}} | ||
} | ||
|
||
test {DataType: RM_SaveDataTypeToString(), RM_LoadDataTypeFromString() work} { | ||
r datatype.set dtkey -1111 MyString | ||
set encoded [r datatype.dump dtkey] | ||
|
||
r datatype.restore dtkeycopy $encoded | ||
assert {[r datatype.get dtkeycopy] eq {-1111 MyString}} | ||
} | ||
|
||
test {DataType: Handle truncated RM_LoadDataTypeFromString()} { | ||
r datatype.set dtkey -1111 MyString | ||
set encoded [r datatype.dump dtkey] | ||
set truncated [string range $encoded 0 end-1] | ||
|
||
catch {r datatype.restore dtkeycopy $truncated} e | ||
set e | ||
} {*Invalid*} | ||
} |