Modules: add RM_LoadDataTypeFromStringEncver (#9537)
adding an advanced api to enable loading data that was sereialized with a specific encoding version
This commit is contained in:
parent
d715655f16
commit
ffafb434fb
16
src/module.c
16
src/module.c
@ -5722,8 +5722,8 @@ void RM_DigestEndSequence(RedisModuleDigest *md) {
|
||||
memset(md->o,0,sizeof(md->o));
|
||||
}
|
||||
|
||||
/* Decode a serialized representation of a module data type 'mt' from string
|
||||
* 'str' and return a newly allocated value, or NULL if decoding failed.
|
||||
/* Decode a serialized representation of a module data type 'mt', in a specific encoding version 'encver'
|
||||
* from string 'str' and return a newly allocated value, or NULL if decoding failed.
|
||||
*
|
||||
* This call basically reuses the 'rdb_load' callback which module data types
|
||||
* implement in order to allow a module to arbitrarily serialize/de-serialize
|
||||
@ -5736,7 +5736,7 @@ void RM_DigestEndSequence(RedisModuleDigest *md) {
|
||||
* If this is NOT done, Redis will handle corrupted (or just truncated) serialized
|
||||
* data by producing an error message and terminating the process.
|
||||
*/
|
||||
void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *mt) {
|
||||
void *RM_LoadDataTypeFromStringEncver(const RedisModuleString *str, const moduleType *mt, int encver) {
|
||||
rio payload;
|
||||
RedisModuleIO io;
|
||||
void *ret;
|
||||
@ -5748,7 +5748,7 @@ void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *
|
||||
* need to make sure we read the same.
|
||||
*/
|
||||
io.ver = 2;
|
||||
ret = mt->rdb_load(&io,0);
|
||||
ret = mt->rdb_load(&io,encver);
|
||||
if (io.ctx) {
|
||||
moduleFreeContext(io.ctx);
|
||||
zfree(io.ctx);
|
||||
@ -5756,6 +5756,13 @@ void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Similar to RM_LoadDataTypeFromStringEncver, original version of the API, kept
|
||||
* for backward compatibility.
|
||||
*/
|
||||
void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *mt) {
|
||||
return RM_LoadDataTypeFromStringEncver(str, mt, 0);
|
||||
}
|
||||
|
||||
/* Encode a module data type 'mt' value 'data' into serialized form, and return it
|
||||
* as a newly allocated RedisModuleString.
|
||||
*
|
||||
@ -10352,6 +10359,7 @@ void moduleRegisterCoreAPI(void) {
|
||||
REGISTER_API(LoadLongDouble);
|
||||
REGISTER_API(SaveDataTypeToString);
|
||||
REGISTER_API(LoadDataTypeFromString);
|
||||
REGISTER_API(LoadDataTypeFromStringEncver);
|
||||
REGISTER_API(EmitAOF);
|
||||
REGISTER_API(Log);
|
||||
REGISTER_API(LogIOError);
|
||||
|
@ -746,6 +746,7 @@ REDISMODULE_API float (*RedisModule_LoadFloat)(RedisModuleIO *io) REDISMODULE_AT
|
||||
REDISMODULE_API void (*RedisModule_SaveLongDouble)(RedisModuleIO *io, long double value) REDISMODULE_ATTR;
|
||||
REDISMODULE_API long double (*RedisModule_LoadLongDouble)(RedisModuleIO *io) REDISMODULE_ATTR;
|
||||
REDISMODULE_API void * (*RedisModule_LoadDataTypeFromString)(const RedisModuleString *str, const RedisModuleType *mt) REDISMODULE_ATTR;
|
||||
REDISMODULE_API void * (*RedisModule_LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_SaveDataTypeToString)(RedisModuleCtx *ctx, void *data, const RedisModuleType *mt) REDISMODULE_ATTR;
|
||||
REDISMODULE_API void (*RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4);
|
||||
REDISMODULE_API void (*RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4);
|
||||
@ -1062,6 +1063,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(LoadLongDouble);
|
||||
REDISMODULE_GET_API(SaveDataTypeToString);
|
||||
REDISMODULE_GET_API(LoadDataTypeFromString);
|
||||
REDISMODULE_GET_API(LoadDataTypeFromStringEncver);
|
||||
REDISMODULE_GET_API(EmitAOF);
|
||||
REDISMODULE_GET_API(Log);
|
||||
REDISMODULE_GET_API(LogIOError);
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "redismodule.h"
|
||||
|
||||
static RedisModuleType *datatype = NULL;
|
||||
static int load_encver = 0;
|
||||
|
||||
#define DATATYPE_ENC_VER 1
|
||||
|
||||
typedef struct {
|
||||
long long intval;
|
||||
@ -12,8 +15,7 @@ typedef struct {
|
||||
} DataType;
|
||||
|
||||
static void *datatype_load(RedisModuleIO *io, int encver) {
|
||||
(void) encver;
|
||||
|
||||
load_encver = encver;
|
||||
int intval = RedisModule_LoadSigned(io);
|
||||
if (RedisModule_IsIOError(io)) return NULL;
|
||||
|
||||
@ -76,7 +78,7 @@ static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
long long intval;
|
||||
|
||||
if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithError(ctx, "Invalid integr value");
|
||||
RedisModule_ReplyWithError(ctx, "Invalid integer value");
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
@ -94,12 +96,18 @@ static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
}
|
||||
|
||||
static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc != 3) {
|
||||
if (argc != 4) {
|
||||
RedisModule_WrongArity(ctx);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
DataType *dt = RedisModule_LoadDataTypeFromString(argv[2], datatype);
|
||||
long long encver;
|
||||
if (RedisModule_StringToLongLong(argv[3], &encver) != REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithError(ctx, "Invalid integer value");
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
DataType *dt = RedisModule_LoadDataTypeFromStringEncver(argv[2], datatype, encver);
|
||||
if (!dt) {
|
||||
RedisModule_ReplyWithError(ctx, "Invalid data");
|
||||
return REDISMODULE_OK;
|
||||
@ -108,7 +116,7 @@ static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int a
|
||||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
|
||||
RedisModule_ModuleTypeSetValue(key, datatype, dt);
|
||||
RedisModule_CloseKey(key);
|
||||
RedisModule_ReplyWithSimpleString(ctx, "OK");
|
||||
RedisModule_ReplyWithLongLong(ctx, load_encver);
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
@ -181,7 +189,7 @@ 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)
|
||||
if (RedisModule_Init(ctx,"datatype",DATATYPE_ENC_VER,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS);
|
||||
|
@ -8,20 +8,20 @@ start_server {tags {"modules"}} {
|
||||
assert {[r datatype.get dtkey] eq {100 stringval}}
|
||||
}
|
||||
|
||||
test {DataType: RM_SaveDataTypeToString(), RM_LoadDataTypeFromString() work} {
|
||||
test {DataType: RM_SaveDataTypeToString(), RM_LoadDataTypeFromStringEncver() work} {
|
||||
r datatype.set dtkey -1111 MyString
|
||||
set encoded [r datatype.dump dtkey]
|
||||
|
||||
r datatype.restore dtkeycopy $encoded
|
||||
assert {[r datatype.restore dtkeycopy $encoded 4] eq {4}}
|
||||
assert {[r datatype.get dtkeycopy] eq {-1111 MyString}}
|
||||
}
|
||||
|
||||
test {DataType: Handle truncated RM_LoadDataTypeFromString()} {
|
||||
test {DataType: Handle truncated RM_LoadDataTypeFromStringEncver()} {
|
||||
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
|
||||
catch {r datatype.restore dtkeycopy $truncated 4} e
|
||||
set e
|
||||
} {*Invalid*}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user