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:
Hanna Fadida 2021-09-30 11:21:32 +03:00 committed by GitHub
parent d715655f16
commit ffafb434fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 15 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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*}