1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
diff -up ./src/config.c.loadmod ./src/config.c
--- ./src/config.c.loadmod 2026-04-28 18:32:37.000000000 +0200
+++ ./src/config.c 2026-04-29 09:34:55.668568785 +0200
@@ -455,6 +455,8 @@ static int updateClientOutputBufferLimit
* within conf file parsing. This is only needed to support the deprecated
* abnormal aggregate `save T C` functionality. Remove in the future. */
static int reading_config_file;
+/* support detecting include vs main config file */
+static int reading_include_file = 0;
void loadServerConfigFromString(sds config) {
deprecatedConfig deprecated_configs[] = {
@@ -547,7 +549,9 @@ void loadServerConfigFromString(sds conf
/* Execute config directives */
if (!strcasecmp(argv[0], "include") && argc == 2) {
+ reading_include_file = 1;
loadServerConfig(argv[1], 0, NULL);
+ reading_include_file = 0;
} else if (!strcasecmp(argv[0], "rename-command") && argc == 3) {
struct serverCommand *cmd = lookupCommandBySds(argv[1]);
@@ -580,7 +584,7 @@ void loadServerConfigFromString(sds conf
goto loaderr;
}
} else if (!strcasecmp(argv[0], "loadmodule") && argc >= 2) {
- moduleEnqueueLoadModule(argv[1], &argv[2], argc - 2);
+ moduleEnqueueLoadModule(argv[1], &argv[2], argc - 2, reading_include_file);
} else if (strchr(argv[0], '.')) {
if (argc < 2) {
err = "Module config specified without value";
@@ -1625,7 +1629,7 @@ void rewriteConfigLoadmoduleOption(struc
struct ValkeyModule *module = dictGetVal(de);
if (module->is_static_module) continue;
line = moduleLoadQueueEntryToLoadmoduleOptionStr(module, "loadmodule");
- rewriteConfigRewriteLine(state, "loadmodule", line, 1);
+ if (line) rewriteConfigRewriteLine(state, "loadmodule", line, 1);
}
dictReleaseIterator(di);
/* Mark "loadmodule" as processed in case modules is empty. */
diff -up ./src/module.c.loadmod ./src/module.c
--- ./src/module.c.loadmod 2026-04-28 18:32:37.000000000 +0200
+++ ./src/module.c 2026-04-29 09:47:30.216571253 +0200
@@ -83,6 +83,7 @@
struct moduleLoadQueueEntry {
sds path;
+ int from_include;
int argc;
robj **argv;
};
@@ -679,7 +680,7 @@ void freeClientModuleData(client *c) {
c->module_data = NULL;
}
-void moduleEnqueueLoadModule(sds path, sds *argv, int argc) {
+void moduleEnqueueLoadModule(sds path, sds *argv, int argc, int from_include) {
int i;
struct moduleLoadQueueEntry *loadmod;
@@ -687,6 +688,7 @@ void moduleEnqueueLoadModule(sds path, s
loadmod->argv = argc ? zmalloc(sizeof(robj *) * argc) : NULL;
loadmod->path = sdsnew(path);
loadmod->argc = argc;
+ loadmod->from_include = from_include;
for (i = 0; i < argc; i++) {
loadmod->argv[i] = createRawStringObject(argv[i], sdslen(argv[i]));
}
@@ -697,6 +699,10 @@ sds moduleLoadQueueEntryToLoadmoduleOpti
const char *config_option_str) {
sds line;
+ if (module->loadmod->from_include) {
+ /* no need to add as already from config */
+ return NULL;
+ }
line = sdsnew(config_option_str);
line = sdscatlen(line, " ", 1);
line = sdscatsds(line, module->loadmod->path);
@@ -13148,7 +13154,7 @@ void moduleLoadFromQueue(void) {
listRewind(server.loadmodule_queue, &li);
while ((ln = listNext(&li))) {
struct moduleLoadQueueEntry *loadmod = ln->value;
- if (moduleLoad(loadmod->path, (void **)loadmod->argv, loadmod->argc, 0) == C_ERR) {
+ if (moduleLoad(loadmod->path, (void **)loadmod->argv, loadmod->argc, 0, loadmod->from_include) == C_ERR) {
serverLog(LL_WARNING, "Can't load module from %s: server aborting", loadmod->path);
exit(1);
}
@@ -13346,7 +13352,7 @@ static int moduleInitPostOnLoadResolved(
void **module_argv,
int module_argc,
int is_loadex,
- int is_static) {
+ int is_static, int from_include) {
ValkeyModuleCtx ctx;
moduleCreateContext(&ctx, NULL, VALKEYMODULE_CTX_TEMP_CLIENT); /* We pass NULL since we don't have a module yet. */
if (onload((void *)&ctx, module_argv, module_argc) == VALKEYMODULE_ERR) {
@@ -13383,6 +13389,7 @@ static int moduleInitPostOnLoadResolved(
ctx.module->loadmod->path = sdsnew(display_name);
ctx.module->loadmod->argv = module_argc ? zmalloc(sizeof(robj *) * module_argc) : NULL;
ctx.module->loadmod->argc = module_argc;
+ ctx.module->loadmod->from_include = from_include;
for (int i = 0; i < module_argc; i++) {
ctx.module->loadmod->argv[i] = module_argv[i];
incrRefCount(ctx.module->loadmod->argv[i]);
@@ -13427,7 +13434,7 @@ static int moduleInitPostOnLoadResolved(
/* Load a module and initialize it. On success C_OK is returned, otherwise
* C_ERR is returned. */
-int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loadex) {
+int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loadex, int from_include) {
ModuleLoadFunc onload;
void *handle;
@@ -13476,7 +13483,7 @@ int moduleLoad(const char *path, void **
path);
return C_ERR;
}
- return moduleInitPostOnLoadResolved(onload, handle, path, module_argv, module_argc, is_loadex, 0);
+ return moduleInitPostOnLoadResolved(onload, handle, path, module_argv, module_argc, is_loadex, 0, from_include);
}
/* Resolve a symbol from a statically linked module. The symbol is looked up
@@ -13542,7 +13549,7 @@ int moduleLoadStatic(const char *module_
return C_ERR;
}
return moduleInitPostOnLoadResolved(onload, handle, module_name, module_argv, module_argc,
- is_loadex, 1);
+ is_loadex, 1, 1);
}
static int moduleUnloadInternal(struct ValkeyModule *module, const char **errmsg) {
@@ -14582,7 +14589,7 @@ void moduleCommand(client *c) {
argv = &c->argv[3];
}
- if (moduleLoad(objectGetVal(c->argv[2]), (void **)argv, argc, 0) == C_OK)
+ if (moduleLoad(objectGetVal(c->argv[2]), (void **)argv, argc, 0, 0) == C_OK)
addReply(c, shared.ok);
else
addReplyError(c, "Error loading the extension. Please check the server logs.");
@@ -14597,7 +14604,7 @@ void moduleCommand(client *c) {
/* If this is a loadex command we want to populate server.module_configs_queue with
* sds NAME VALUE pairs. We also want to increment argv to just after ARGS, if supplied. */
if (parseLoadexArguments((ValkeyModuleString ***)&argv, &argc) == VALKEYMODULE_OK &&
- moduleLoad(objectGetVal(c->argv[2]), (void **)argv, argc, 1) == C_OK)
+ moduleLoad(objectGetVal(c->argv[2]), (void **)argv, argc, 1, 0) == C_OK)
addReply(c, shared.ok);
else {
dictEmpty(server.module_configs_queue, NULL);
diff -up ./src/module.h.loadmod ./src/module.h
--- ./src/module.h.loadmod 2026-04-28 18:32:37.000000000 +0200
+++ ./src/module.h 2026-04-29 09:35:56.783998866 +0200
@@ -174,7 +174,7 @@ static inline void moduleInitDigestConte
memset(mdvar->x, 0, sizeof(mdvar->x));
}
-void moduleEnqueueLoadModule(sds path, sds *argv, int argc);
+void moduleEnqueueLoadModule(sds path, sds *argv, int argc, int from_include);
sds moduleLoadQueueEntryToLoadmoduleOptionStr(ValkeyModule *module,
const char *config_option_str);
ValkeyModuleCtx *moduleAllocateContext(void);
@@ -186,7 +186,7 @@ void moduleFreeContext(ValkeyModuleCtx *
void moduleInitModulesSystem(void);
void moduleInitModulesSystemLast(void);
void modulesCron(void);
-int moduleLoad(const char *path, void **argv, int argc, int is_loadex);
+int moduleLoad(const char *path, void **argv, int argc, int is_loadex, int from_include);
int moduleLoadStatic(const char *path, void **argv, int argc, int is_loadex);
int moduleUnload(sds name, const char **errmsg);
void moduleUnloadAllModules(void);
diff -up ./src/server.c.loadmod ./src/server.c
|