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)); memset(md->o,0,sizeof(md->o));
} }
/* Decode a serialized representation of a module data type 'mt' from string /* Decode a serialized representation of a module data type 'mt', in a specific encoding version 'encver'
* 'str' and return a newly allocated value, or NULL if decoding failed. * 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 * This call basically reuses the 'rdb_load' callback which module data types
* implement in order to allow a module to arbitrarily serialize/de-serialize * 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 * If this is NOT done, Redis will handle corrupted (or just truncated) serialized
* data by producing an error message and terminating the process. * 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; rio payload;
RedisModuleIO io; RedisModuleIO io;
void *ret; void *ret;
@ -5748,7 +5748,7 @@ void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *
* need to make sure we read the same. * need to make sure we read the same.
*/ */
io.ver = 2; io.ver = 2;
ret = mt->rdb_load(&io,0); ret = mt->rdb_load(&io,encver);
if (io.ctx) { if (io.ctx) {
moduleFreeContext(io.ctx); moduleFreeContext(io.ctx);
zfree(io.ctx); zfree(io.ctx);
@ -5756,6 +5756,13 @@ void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *
return ret; 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 /* Encode a module data type 'mt' value 'data' into serialized form, and return it
* as a newly allocated RedisModuleString. * as a newly allocated RedisModuleString.
* *
@ -10352,6 +10359,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(LoadLongDouble); REGISTER_API(LoadLongDouble);
REGISTER_API(SaveDataTypeToString); REGISTER_API(SaveDataTypeToString);
REGISTER_API(LoadDataTypeFromString); REGISTER_API(LoadDataTypeFromString);
REGISTER_API(LoadDataTypeFromStringEncver);
REGISTER_API(EmitAOF); REGISTER_API(EmitAOF);
REGISTER_API(Log); REGISTER_API(Log);
REGISTER_API(LogIOError); 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 void (*RedisModule_SaveLongDouble)(RedisModuleIO *io, long double value) REDISMODULE_ATTR;
REDISMODULE_API long double (*RedisModule_LoadLongDouble)(RedisModuleIO *io) 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_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 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_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); 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(LoadLongDouble);
REDISMODULE_GET_API(SaveDataTypeToString); REDISMODULE_GET_API(SaveDataTypeToString);
REDISMODULE_GET_API(LoadDataTypeFromString); REDISMODULE_GET_API(LoadDataTypeFromString);
REDISMODULE_GET_API(LoadDataTypeFromStringEncver);
REDISMODULE_GET_API(EmitAOF); REDISMODULE_GET_API(EmitAOF);
REDISMODULE_GET_API(Log); REDISMODULE_GET_API(Log);
REDISMODULE_GET_API(LogIOError); REDISMODULE_GET_API(LogIOError);

View File

@ -5,6 +5,9 @@
#include "redismodule.h" #include "redismodule.h"
static RedisModuleType *datatype = NULL; static RedisModuleType *datatype = NULL;
static int load_encver = 0;
#define DATATYPE_ENC_VER 1
typedef struct { typedef struct {
long long intval; long long intval;
@ -12,8 +15,7 @@ typedef struct {
} DataType; } DataType;
static void *datatype_load(RedisModuleIO *io, int encver) { static void *datatype_load(RedisModuleIO *io, int encver) {
(void) encver; load_encver = encver;
int intval = RedisModule_LoadSigned(io); int intval = RedisModule_LoadSigned(io);
if (RedisModule_IsIOError(io)) return NULL; if (RedisModule_IsIOError(io)) return NULL;
@ -76,7 +78,7 @@ static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
long long intval; long long intval;
if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) { if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integr value"); RedisModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; 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) { static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 3) { if (argc != 4) {
RedisModule_WrongArity(ctx); RedisModule_WrongArity(ctx);
return REDISMODULE_OK; 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) { if (!dt) {
RedisModule_ReplyWithError(ctx, "Invalid data"); RedisModule_ReplyWithError(ctx, "Invalid data");
return REDISMODULE_OK; 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); RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
RedisModule_ModuleTypeSetValue(key, datatype, dt); RedisModule_ModuleTypeSetValue(key, datatype, dt);
RedisModule_CloseKey(key); RedisModule_CloseKey(key);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedisModule_ReplyWithLongLong(ctx, load_encver);
return REDISMODULE_OK; return REDISMODULE_OK;
} }
@ -181,7 +189,7 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); 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; return REDISMODULE_ERR;
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS); 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}} 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 r datatype.set dtkey -1111 MyString
set encoded [r datatype.dump dtkey] 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}} 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 r datatype.set dtkey -1111 MyString
set encoded [r datatype.dump dtkey] set encoded [r datatype.dump dtkey]
set truncated [string range $encoded 0 end-1] 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 set e
} {*Invalid*} } {*Invalid*}