-
Notifications
You must be signed in to change notification settings - Fork 952
Adding support for DumpSerializedValue API #2331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: unstable
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall.
This is a new module API, so I believe this requires voting @valkey-io/core-team. Please vote 👍 / 👎
@@ -7532,6 +7533,32 @@ ValkeyModuleString *VM_SaveDataTypeToString(ValkeyModuleCtx *ctx, void *data, co | |||
} | |||
} | |||
|
|||
/** | |||
* Serialize the value of a given key from the database of the module context's client. | |||
* If the serialization fails for any reason (e.g. key doesn't exist, or rdbSaveObject() fails), return NULL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't the module benefit from knowing the actual reason of failure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When does this operation rdbSaveObject
fail ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rdbSaveObject can fail when writing out to network, but it never fails when pushing an object in-memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought so. We can simplify the comment to if NULL, the key doesn't exists.
src/module.c
Outdated
// Create a ValkeyModuleString (robj*) with the result SDS and return it. | ||
sds result = rdb.io.buffer.ptr; | ||
ValkeyModuleString *o = createObject(OBJ_STRING, result); | ||
if (ctx != NULL) autoMemoryAdd(ctx, VALKEYMODULE_AM_STRING, o); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on the entry of the method we check if ctx is NULL, we perform an early exit so we could avoid the NULL check here.
if (ctx != NULL) autoMemoryAdd(ctx, VALKEYMODULE_AM_STRING, o); | |
autoMemoryAdd(ctx, VALKEYMODULE_AM_STRING, o); |
src/module.c
Outdated
if (value == NULL) { | ||
return NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: consistent with your code style
if (value == NULL) { | |
return NULL; | |
} | |
if (!value) { | |
return NULL; | |
} |
src/redismodule.h
Outdated
@@ -362,6 +362,7 @@ | |||
#define RedisModule_SelectDb ValkeyModule_SelectDb | |||
#define RedisModule_KeyExists ValkeyModule_KeyExists | |||
#define RedisModule_OpenKey ValkeyModule_OpenKey | |||
#define RedisModule_SaveObjectToString ValkeyModule_SaveObjectToString |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we keep adding this for new API(s) as well? @PingXie
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, these are only for redis module API compat. We can add it if redis has it imo, but otherwise not.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## unstable #2331 +/- ##
============================================
- Coverage 71.43% 71.42% -0.01%
============================================
Files 123 123
Lines 66908 67101 +193
============================================
+ Hits 47795 47930 +135
- Misses 19113 19171 +58
🚀 New features to boost your workflow:
|
I'm fine with this API but I would like to know more about the use case(s). What module do you want to use it for and why? |
src/module.c
Outdated
* If the serialization fails for any reason (e.g. key doesn't exist, or rdbSaveObject() fails), return NULL | ||
* Otherwise return ValkeyModuleString which contains the serialized value for the key. | ||
*/ | ||
ValkeyModuleString *VM_SaveObjectToString(ValkeyModuleCtx *ctx, ValkeyModuleString *key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have a better name since it basically retruns serialized value?
e.g., VM_DumpSerializedValue
src/module.c
Outdated
if (value == NULL) { | ||
return NULL; | ||
} | ||
rio rdb; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
rio rdb; | |
rio payload; |
tests/unit/moduleapi/datatype.tcl
Outdated
|
||
test {DataType: Save Object to String correctly serialzies strings} { | ||
r set key value | ||
set serialized [r datatype.save_object key] | ||
r restore newkey 0 $serialized | ||
r get newkey | ||
} {value} | ||
|
||
test {DataType: Save Object to String correctly serializes hashes} { | ||
r hset myhash field1 myvalue | ||
set serialized [r datatype.save_object myhash] | ||
r restore newhash 0 $serialized | ||
r hgetall newhash | ||
} {field1 myvalue} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add a test for nonexistent key case
The team is exploring change data capture use case around Valkey. On a key space notification to the module, they would like to create a serialized dump of the value and pass it forward. |
Change data capture can be used for implementing custom replication and AOF-like backups, etc.? If the new API returns a dump of a key in RDB format, it's very similar to the DUMP command? like VM_Call(DUMP) |
Yeah, basically the same. Talked to @QuChen88 about this yesterday. Do we plan on introducing more information to the module API or does |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK with the high level proposal, but think we should flow through the normal mechanism of opening a key instead of a new way to access keys. Otherwise I agree with others that the right way would be to do VM_Call + DUMP.
src/module.c
Outdated
return NULL; | ||
} | ||
|
||
int flags = LOOKUP_NOTOUCH | LOOKUP_NONOTIFY | LOOKUP_NOEXPIRE | LOOKUP_NOEFFECTS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int flags = LOOKUP_NOTOUCH | LOOKUP_NONOTIFY | LOOKUP_NOEXPIRE | LOOKUP_NOEFFECTS; | |
int flags = LOOKUP_NOEFFECTS; |
LOOKUP_NOEFFECTS implies the other three :)
@@ -7532,6 +7533,32 @@ ValkeyModuleString *VM_SaveDataTypeToString(ValkeyModuleCtx *ctx, void *data, co | |||
} | |||
} | |||
|
|||
/** | |||
* Serialize the value of a given key from the database of the module context's client. | |||
* If the serialization fails for any reason (e.g. key doesn't exist, or rdbSaveObject() fails), return NULL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rdbSaveObject can fail when writing out to network, but it never fails when pushing an object in-memory.
* If the serialization fails for any reason (e.g. key doesn't exist, or rdbSaveObject() fails), return NULL | ||
* Otherwise return ValkeyModuleString which contains the serialized value for the key. | ||
*/ | ||
ValkeyModuleString *VM_DumpSerializedValue(ValkeyModuleCtx *ctx, ValkeyModuleString *key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the more correct API would be to operate on an already opened Key. The handling of the DB parameters here isn't quite right (it will always be DB zero). something like:
ValkeyModuleString *VM_DumpSerializedValue(ValkeyModuleKey *key);
Yes this module API is for change data capture where we can capture keyspace notifications and generate a message containing the information about key name / type of update / serialized value post modification, and making the changes available elsewhere in a different system. Doing it via |
Signed-off-by: Carolyn Dorantes <cdorants@amazon.com>
@QuChen88 yes VM_Call has a lot of overhead. It's just good to point out the equivalents and alternatives. Maybe since this is equivalent to the DUMP command, should we call it VM_Dump? What about VM_Restore, do we need it too? Dump/restore are used together and providing both maybe be more complete? |
@zuiderkwast For the API name, I think either Even though A couple of questions here about the implement for
|
I have no strong opinion about the name. DumpSerializedValue is OK. It should take a ValkeyModuleKey though. We can postpone Restore to a separate PR if it's non-trivial. (It too should operate on ValkeyNoduleKey probably.) |
I am strongly against creating new module APIs as an alternative for calling existing commands. In this case, in particular, as far as I can tell, there has been no measurements to show that We need to address API changes with caution. |
I looked into the implementation of I agree that in the meantime we can proceed with |
The purpose of this API is for Modules to be able to access a key and retrieve its associated value in order to serialize that value. This allows modules to extract and store data in a format that can later be reconstructed.
A use case is when building a CDC module, we need to generate the serialized version of any given key (of any data type). This allows for any specific key and its value(s) to be logged in the CDC message.