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));
|
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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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*}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user