summaryrefslogtreecommitdiff
path: root/src/rdb.c
diff options
context:
space:
mode:
authorMeir Shpilraien (Spielrein) <meir@redis.com>2022-04-05 10:27:24 +0300
committerGitHub <noreply@github.com>2022-04-05 10:27:24 +0300
commitae020e3d5665e46dbd2704b46b6ad207dd4471d9 (patch)
tree607ca81a18206b91131b94f34d25c596d30f3a88 /src/rdb.c
parent2db0d898f8d9daef34a6b9678a905a51cc43c298 (diff)
downloadredis-ae020e3d5665e46dbd2704b46b6ad207dd4471d9.tar.gz
Functions: Move library meta data to be part of the library payload. (#10500)
## Move library meta data to be part of the library payload. Following the discussion on https://github.com/redis/redis/issues/10429 and the intention to add (in the future) library versioning support, we believe that the entire library metadata (like name and engine) should be part of the library payload and not provided by the `FUNCTION LOAD` command. The reasoning behind this is that the programmer who developed the library should be the one who set those values (name, engine, and in the future also version). **It is not the responsibility of the admin who load the library into the database.** The PR moves all the library metadata (engine and function name) to be part of the library payload. The metadata needs to be provided on the first line of the payload using the shebang format (`#!<engine> name=<name>`), example: ```lua #!lua name=test redis.register_function('foo', function() return 1 end) ``` The above script will run on the Lua engine and will create a library called `test`. ## API Changes (compare to 7.0 rc2) * `FUNCTION LOAD` command was change and now it simply gets the library payload and extract the engine and name from the payload. In addition, the command will now return the function name which can later be used on `FUNCTION DELETE` and `FUNCTION LIST`. * The description field was completely removed from`FUNCTION LOAD`, and `FUNCTION LIST` ## Breaking Changes (compare to 7.0 rc2) * Library description was removed (we can re-add it in the future either as part of the shebang line or an additional line). * Loading an AOF file that was generated by either 7.0 rc1 or 7.0 rc2 will fail because the old command syntax is invalid. ## Notes * Loading an RDB file that was generated by rc1 / rc2 **is** supported, Redis will automatically add the shebang to the libraries payloads (we can probably delete that code after 7.0.3 or so since there's no need to keep supporting upgrades from an RC build).
Diffstat (limited to 'src/rdb.c')
-rw-r--r--src/rdb.c108
1 files changed, 58 insertions, 50 deletions
diff --git a/src/rdb.c b/src/rdb.c
index d5f853dd8..0283630f7 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -1242,24 +1242,9 @@ ssize_t rdbSaveFunctions(rio *rdb) {
ssize_t written = 0;
ssize_t ret;
while ((entry = dictNext(iter))) {
- if ((ret = rdbSaveType(rdb, RDB_OPCODE_FUNCTION)) < 0) goto werr;
+ if ((ret = rdbSaveType(rdb, RDB_OPCODE_FUNCTION2)) < 0) goto werr;
written += ret;
functionLibInfo *li = dictGetVal(entry);
- if ((ret = rdbSaveRawString(rdb, (unsigned char *) li->name, sdslen(li->name))) < 0) goto werr;
- written += ret;
- if ((ret = rdbSaveRawString(rdb, (unsigned char *) li->ei->name, sdslen(li->ei->name))) < 0) goto werr;
- written += ret;
- if (li->desc) {
- /* desc exists */
- if ((ret = rdbSaveLen(rdb, 1)) < 0) goto werr;
- written += ret;
- if ((ret = rdbSaveRawString(rdb, (unsigned char *) li->desc, sdslen(li->desc))) < 0) goto werr;
- written += ret;
- } else {
- /* desc not exists */
- if ((ret = rdbSaveLen(rdb, 0)) < 0) goto werr;
- written += ret;
- }
if ((ret = rdbSaveRawString(rdb, (unsigned char *) li->code, sdslen(li->code))) < 0) goto werr;
written += ret;
}
@@ -2811,56 +2796,79 @@ void rdbLoadProgressCallback(rio *r, const void *buf, size_t len) {
*
* The lib_ctx argument is also optional. If NULL is given, only verify rdb
* structure with out performing the actual functions loading. */
-int rdbFunctionLoad(rio *rdb, int ver, functionsLibCtx* lib_ctx, int rdbflags, sds *err) {
+int rdbFunctionLoad(rio *rdb, int ver, functionsLibCtx* lib_ctx, int type, int rdbflags, sds *err) {
UNUSED(ver);
- sds name = NULL;
- sds engine_name = NULL;
- sds desc = NULL;
- sds blob = NULL;
- uint64_t has_desc;
sds error = NULL;
+ sds final_payload = NULL;
int res = C_ERR;
- if (!(name = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
- error = sdsnew("Failed loading library name");
- goto error;
- }
+ if (type == RDB_OPCODE_FUNCTION) {
+ /* RDB that was generated on versions 7.0 rc1 and 7.0 rc2 has another
+ * an old format that contains the library name, engine and description.
+ * To support this format we must read those values. */
+ sds name = NULL;
+ sds engine_name = NULL;
+ sds desc = NULL;
+ sds blob = NULL;
+ uint64_t has_desc;
+
+ if (!(name = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
+ error = sdsnew("Failed loading library name");
+ goto cleanup;
+ }
- if (!(engine_name = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
- error = sdsnew("Failed loading engine name");
- goto error;
- }
+ if (!(engine_name = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
+ error = sdsnew("Failed loading engine name");
+ goto cleanup;
+ }
- if ((has_desc = rdbLoadLen(rdb, NULL)) == RDB_LENERR) {
- error = sdsnew("Failed loading library description indicator");
- goto error;
- }
+ if ((has_desc = rdbLoadLen(rdb, NULL)) == RDB_LENERR) {
+ error = sdsnew("Failed loading library description indicator");
+ goto cleanup;
+ }
- if (has_desc && !(desc = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
- error = sdsnew("Failed loading library description");
- goto error;
- }
+ if (has_desc && !(desc = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
+ error = sdsnew("Failed loading library description");
+ goto cleanup;
+ }
- if (!(blob = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
- error = sdsnew("Failed loading library blob");
- goto error;
+ if (!(blob = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
+ error = sdsnew("Failed loading library blob");
+ goto cleanup;
+ }
+ /* Translate old format (versions 7.0 rc1 and 7.0 rc2) to new format.
+ * The new format has the library name and engine inside the script payload.
+ * Add those parameters to the original script payload (ignore the description if exists). */
+ final_payload = sdscatfmt(sdsempty(), "#!%s name=%s\n%s", engine_name, name, blob);
+cleanup:
+ if (name) sdsfree(name);
+ if (engine_name) sdsfree(engine_name);
+ if (desc) sdsfree(desc);
+ if (blob) sdsfree(blob);
+ if (error) goto done;
+ } else if (type == RDB_OPCODE_FUNCTION2) {
+ if (!(final_payload = rdbGenericLoadStringObject(rdb, RDB_LOAD_SDS, NULL))) {
+ error = sdsnew("Failed loading library payload");
+ goto done;
+ }
+ } else {
+ serverPanic("Bad function type was given to rdbFunctionLoad");
}
if (lib_ctx) {
- if (functionsCreateWithLibraryCtx(name, engine_name, desc, blob, rdbflags & RDBFLAGS_ALLOW_DUP, &error, lib_ctx) != C_OK) {
+ sds library_name = NULL;
+ if (!(library_name = functionsCreateWithLibraryCtx(final_payload, rdbflags & RDBFLAGS_ALLOW_DUP, &error, lib_ctx))) {
if (!error) {
error = sdsnew("Failed creating the library");
}
- goto error;
+ goto done;
}
+ sdsfree(library_name);
}
res = C_OK;
-error:
- if (name) sdsfree(name);
- if (engine_name) sdsfree(engine_name);
- if (desc) sdsfree(desc);
- if (blob) sdsfree(blob);
+done:
+ if (final_payload) sdsfree(final_payload);
if (error) {
if (err) {
*err = error;
@@ -3091,9 +3099,9 @@ int rdbLoadRioWithLoadingCtx(rio *rdb, int rdbflags, rdbSaveInfo *rsi, rdbLoadin
decrRefCount(aux);
continue; /* Read next opcode. */
}
- } else if (type == RDB_OPCODE_FUNCTION) {
+ } else if (type == RDB_OPCODE_FUNCTION || type == RDB_OPCODE_FUNCTION2) {
sds err = NULL;
- if (rdbFunctionLoad(rdb, rdbver, rdb_loading_ctx->functions_lib_ctx, rdbflags, &err) != C_OK) {
+ if (rdbFunctionLoad(rdb, rdbver, rdb_loading_ctx->functions_lib_ctx, type, rdbflags, &err) != C_OK) {
serverLog(LL_WARNING,"Failed loading library, %s", err);
sdsfree(err);
goto eoferr;