Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
fb4e0d40
Unverified
Commit
fb4e0d40
authored
Apr 05, 2022
by
Oran Agra
Committed by
GitHub
Apr 05, 2022
Browse files
Merge pull request #10532 from oranagra/7.0-rc3
Release 7.0 rc3
parents
d2b5a579
8b242ef9
Changes
171
Hide whitespace changes
Inline
Side-by-side
src/commands/sentinel-get-master-addr-by-name.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-info-cache.json
View file @
fb4e0d40
...
...
@@ -4,13 +4,20 @@
"complexity"
:
"O(N) where N is the number of instances"
,
"group"
:
"sentinel"
,
"since"
:
"3.2.0"
,
"arity"
:
3
,
"arity"
:
-
3
,
"container"
:
"SENTINEL"
,
"function"
:
"sentinelCommand"
,
"command_flags"
:
[
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"nodename"
,
"type"
:
"string"
,
"multiple"
:
true
}
]
}
}
src/commands/sentinel-is-master-down-by-addr.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,24 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"ip"
,
"type"
:
"string"
},
{
"name"
:
"port"
,
"type"
:
"integer"
},
{
"name"
:
"current-epoch"
,
"type"
:
"integer"
},
{
"name"
:
"runid"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-master.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-monitor.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,24 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"name"
,
"type"
:
"string"
},
{
"name"
:
"ip"
,
"type"
:
"string"
},
{
"name"
:
"port"
,
"type"
:
"integer"
},
{
"name"
:
"quorum"
,
"type"
:
"integer"
}
]
}
}
src/commands/sentinel-remove.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-replicas.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-reset.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"pattern"
,
"type"
:
"pattern"
}
]
}
}
src/commands/sentinel-sentinels.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,12 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
}
]
}
}
src/commands/sentinel-set.json
View file @
fb4e0d40
...
...
@@ -11,6 +11,27 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"master-name"
,
"type"
:
"string"
},
{
"name"
:
"option_value"
,
"type"
:
"block"
,
"multiple"
:
true
,
"arguments"
:
[
{
"name"
:
"option"
,
"type"
:
"string"
},
{
"name"
:
"value"
,
"type"
:
"string"
}
]
}
]
}
}
src/commands/sentinel-simulate-failure.json
View file @
fb4e0d40
...
...
@@ -10,6 +10,28 @@
"ADMIN"
,
"SENTINEL"
,
"ONLY_SENTINEL"
],
"arguments"
:
[
{
"name"
:
"mode"
,
"type"
:
"oneof"
,
"optional"
:
true
,
"multiple"
:
true
,
"arguments"
:
[
{
"name"
:
"crash-after-election"
,
"type"
:
"pure-token"
},
{
"name"
:
"crash-after-promotion"
,
"type"
:
"pure-token"
},
{
"name"
:
"help"
,
"type"
:
"pure-token"
}
]
}
]
}
}
src/commands/shutdown.json
View file @
fb4e0d40
...
...
@@ -9,7 +9,7 @@
"history"
:
[
[
"7.0.0"
,
"Added the `NOW`, `FORCE` and `ABORT` modifiers.
Introduced waiting for lagging replicas before exiting.
"
"Added the `NOW`, `FORCE` and `ABORT` modifiers."
]
],
"command_flags"
:
[
...
...
src/commands/slaveof.json
View file @
fb4e0d40
...
...
@@ -24,7 +24,7 @@
},
{
"name"
:
"port"
,
"type"
:
"
string
"
"type"
:
"
integer
"
}
]
}
...
...
src/commands/sort.json
View file @
fb4e0d40
...
...
@@ -96,7 +96,7 @@
"token"
:
"GET"
,
"name"
:
"pattern"
,
"key_spec_index"
:
1
,
"type"
:
"
string
"
,
"type"
:
"
pattern
"
,
"optional"
:
true
,
"multiple"
:
true
,
"multiple_token"
:
true
...
...
src/commands/sort_ro.json
View file @
fb4e0d40
...
...
@@ -82,7 +82,7 @@
"token"
:
"GET"
,
"name"
:
"pattern"
,
"key_spec_index"
:
1
,
"type"
:
"
string
"
,
"type"
:
"
pattern
"
,
"optional"
:
true
,
"multiple"
:
true
,
"multiple_token"
:
true
...
...
src/commands/spublish.json
View file @
fb4e0d40
{
"SPUBLISH"
:
{
"summary"
:
"Post a message to a shard channel"
,
"complexity"
:
"O(N) where N is the number of clients subscribed to the receiving shard channel."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
3
,
"function"
:
"spublishCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"LOADING"
,
"STALE"
,
"FAST"
,
"MAY_REPLICATE"
],
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
},
{
"name"
:
"message"
,
"type"
:
"string"
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
"SPUBLISH"
:
{
"summary"
:
"Post a message to a shard channel"
,
"complexity"
:
"O(N) where N is the number of clients subscribed to the receiving shard channel."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
3
,
"function"
:
"spublishCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"LOADING"
,
"STALE"
,
"FAST"
,
"MAY_REPLICATE"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
0
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
},
{
"name"
:
"message"
,
"type"
:
"string"
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
0
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
}
src/commands/ssubscribe.json
View file @
fb4e0d40
{
"SSUBSCRIBE"
:
{
"summary"
:
"Listen for messages published to the given shard channels"
,
"complexity"
:
"O(N) where N is the number of shard channels to subscribe to."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-2
,
"function"
:
"ssubscribeCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"NOSCRIPT"
,
"LOADING"
,
"STALE"
],
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
,
"multiple"
:
true
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
"SSUBSCRIBE"
:
{
"summary"
:
"Listen for messages published to the given shard channels"
,
"complexity"
:
"O(N) where N is the number of shard channels to subscribe to."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-2
,
"function"
:
"ssubscribeCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"NOSCRIPT"
,
"LOADING"
,
"STALE"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
-1
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
,
"multiple"
:
true
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
-1
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
}
src/commands/subscribe.json
View file @
fb4e0d40
...
...
@@ -6,12 +6,7 @@
"since"
:
"2.0.0"
,
"arity"
:
-2
,
"function"
:
"subscribeCommand"
,
"history"
:
[
[
"6.2.0"
,
"`RESET` can be called to exit subscribed state."
]
],
"history"
:
[],
"command_flags"
:
[
"PUBSUB"
,
"NOSCRIPT"
,
...
...
src/commands/sunsubscribe.json
View file @
fb4e0d40
{
"SUNSUBSCRIBE"
:
{
"summary"
:
"Stop listening for messages posted to the given shard channels"
,
"complexity"
:
"O(N) where N is the number of clients already subscribed to a channel."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-1
,
"function"
:
"sunsubscribeCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"NOSCRIPT"
,
"LOADING"
,
"STALE"
],
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
,
"optional"
:
true
,
"multiple"
:
true
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
"SUNSUBSCRIBE"
:
{
"summary"
:
"Stop listening for messages posted to the given shard channels"
,
"complexity"
:
"O(N) where N is the number of clients already subscribed to a channel."
,
"group"
:
"pubsub"
,
"since"
:
"7.0.0"
,
"arity"
:
-1
,
"function"
:
"sunsubscribeCommand"
,
"command_flags"
:
[
"PUBSUB"
,
"NOSCRIPT"
,
"LOADING"
,
"STALE"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
-1
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
"arguments"
:
[
{
"name"
:
"channel"
,
"type"
:
"string"
,
"optional"
:
true
,
"multiple"
:
true
}
],
"key_specs"
:
[
{
"flags"
:
[
"NOT_KEY"
],
"begin_search"
:
{
"index"
:
{
"pos"
:
1
}
},
"find_keys"
:
{
"range"
:
{
"lastkey"
:
-1
,
"step"
:
1
,
"limit"
:
0
}
}
}
]
}
}
src/config.c
View file @
fb4e0d40
...
...
@@ -40,11 +40,6 @@
* Config file name-value maps.
*----------------------------------------------------------------------------*/
typedef
struct
configEnum
{
const
char
*
name
;
const
int
val
;
}
configEnum
;
typedef
struct
deprecatedConfig
{
const
char
*
name
;
const
int
argc_min
;
...
...
@@ -168,7 +163,7 @@ int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };
* rewrite. */
typedef
struct
boolConfigData
{
int
*
config
;
/* The pointer to the server config this value is stored in */
const
int
default_value
;
/* The default value of the config on rewrite */
int
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
int
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
}
boolConfigData
;
...
...
@@ -182,7 +177,7 @@ typedef struct stringConfigData {
typedef
struct
sdsConfigData
{
sds
*
config
;
/* Pointer to the server config this value is stored in. */
const
char
*
default_value
;
/* Default value of the config on rewrite. */
char
*
default_value
;
/* Default value of the config on rewrite. */
int
(
*
is_valid_fn
)(
sds
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
int
convert_empty_to_null
;
/* Boolean indicating if empty SDS strings should
be stored as a NULL value. */
...
...
@@ -191,7 +186,7 @@ typedef struct sdsConfigData {
typedef
struct
enumConfigData
{
int
*
config
;
/* The pointer to the server config this value is stored in */
configEnum
*
enum_value
;
/* The underlying enum type this data represents */
const
int
default_value
;
/* The default value of the config on rewrite */
int
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
int
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
}
enumConfigData
;
...
...
@@ -208,11 +203,6 @@ typedef enum numericType {
NUMERIC_TYPE_TIME_T
,
}
numericType
;
#define INTEGER_CONFIG 0
/* No flags means a simple integer configuration */
#define MEMORY_CONFIG (1<<0)
/* Indicates if this value can be loaded as a memory value */
#define PERCENT_CONFIG (1<<1)
/* Indicates if this value can be loaded as a percent (and stored as a negative int) */
#define OCTAL_CONFIG (1<<2)
/* This value uses octal representation */
typedef
struct
numericConfigData
{
union
{
int
*
i
;
...
...
@@ -230,7 +220,7 @@ typedef struct numericConfigData {
numericType
numeric_type
;
/* An enum indicating the type of this value */
long
long
lower_bound
;
/* The lower bound of this numeric value */
long
long
upper_bound
;
/* The upper bound of this numeric value */
const
long
long
default_value
;
/* The default value of the config on rewrite */
long
long
default_value
;
/* The default value of the config on rewrite */
int
(
*
is_valid_fn
)(
long
long
val
,
const
char
**
err
);
/* Optional function to check validity of new value (generic doc above) */
}
numericConfigData
;
...
...
@@ -242,43 +232,44 @@ typedef union typeData {
numericConfigData
numeric
;
}
typeData
;
typedef
struct
standardConfig
standardConfig
;
typedef
int
(
*
apply_fn
)(
const
char
**
err
);
typedef
struct
typeInterface
{
/* Called on server start, to init the server with default value */
void
(
*
init
)(
typeData
data
);
void
(
*
init
)(
standardConfig
*
config
);
/* Called on server startup and CONFIG SET, returns 1 on success,
* 2 meaning no actual change done, 0 on error and can set a verbose err
* string */
int
(
*
set
)(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
);
int
(
*
set
)(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
);
/* Optional: called after `set()` to apply the config change. Used only in
* the context of CONFIG SET. Returns 1 on success, 0 on failure.
* Optionally set err to a static error string. */
apply_fn
apply
;
/* Called on CONFIG GET, returns sds to be used in reply */
sds
(
*
get
)(
typeData
data
);
sds
(
*
get
)(
standardConfig
*
config
);
/* Called on CONFIG REWRITE, required to rewrite the config state */
void
(
*
rewrite
)(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
);
void
(
*
rewrite
)(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
);
}
typeInterface
;
typedef
struct
standardConfig
{
struct
standardConfig
{
const
char
*
name
;
/* The user visible name of this config */
const
char
*
alias
;
/* An alias that can also be used for this config */
const
unsigned
int
flags
;
/* Flags for this specific config */
unsigned
int
flags
;
/* Flags for this specific config */
typeInterface
interface
;
/* The function pointers that define the type interface */
typeData
data
;
/* The type specific data exposed used by the interface */
}
standardConfig
;
configType
type
;
/* The type of config this is. */
void
*
privdata
;
/* privdata for this config, for module configs this is a ModuleConfig struct */
};
#define MODIFIABLE_CONFIG 0
/* This is the implied default for a standard
* config, which is mutable. */
#define IMMUTABLE_CONFIG (1ULL<<0)
/* Can this value only be set at startup? */
#define SENSITIVE_CONFIG (1ULL<<1)
/* Does this value contain sensitive information */
#define DEBUG_CONFIG (1ULL<<2)
/* Values that are useful for debugging. */
#define MULTI_ARG_CONFIG (1ULL<<3)
/* This config receives multiple arguments. */
#define HIDDEN_CONFIG (1ULL<<4)
/* This config is hidden in `config get <pattern>` (used for tests/debugging) */
#define PROTECTED_CONFIG (1ULL<<5)
/* Becomes immutable if enable-protected-configs is enabled. */
#define DENY_LOADING_CONFIG (1ULL<<6)
/* This config is forbidden during loading. */
dict
*
configs
=
NULL
;
/* Runtime config values */
standardConfig
configs
[];
/* Lookup a config by the provided sds string name, or return NULL
* if the config does not exist */
static
standardConfig
*
lookupConfig
(
sds
name
)
{
dictEntry
*
de
=
dictFind
(
configs
,
name
);
return
de
?
dictGetVal
(
de
)
:
NULL
;
}
/*-----------------------------------------------------------------------------
* Enum access functions
...
...
@@ -407,12 +398,6 @@ static int updateClientOutputBufferLimit(sds *args, int arg_len, const char **er
return
1
;
}
void
initConfigValues
()
{
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
(
config
->
interface
.
init
)
config
->
interface
.
init
(
config
->
data
);
}
}
/* Note this is here to support detecting we're running a config set from
* within conf file parsing. This is only needed to support the deprecated
* abnormal aggregate `save T C` functionality. Remove in the future. */
...
...
@@ -458,29 +443,23 @@ void loadServerConfigFromString(char *config) {
sdstolower
(
argv
[
0
]);
/* Iterate the configs that are standard */
int
match
=
0
;
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
((
!
strcasecmp
(
argv
[
0
],
config
->
name
)
||
(
config
->
alias
&&
!
strcasecmp
(
argv
[
0
],
config
->
alias
))))
{
/* For normal single arg configs enforce we have a single argument.
* Note that MULTI_ARG_CONFIGs need to validate arg count on their own */
if
(
!
(
config
->
flags
&
MULTI_ARG_CONFIG
)
&&
argc
!=
2
)
{
err
=
"wrong number of arguments"
;
goto
loaderr
;
}
/* Set config using all arguments that follows */
if
(
!
config
->
interface
.
set
(
config
->
data
,
&
argv
[
1
],
argc
-
1
,
&
err
))
{
goto
loaderr
;
}
match
=
1
;
break
;
standardConfig
*
config
=
lookupConfig
(
argv
[
0
]);
if
(
config
)
{
/* For normal single arg configs enforce we have a single argument.
* Note that MULTI_ARG_CONFIGs need to validate arg count on their own */
if
(
!
(
config
->
flags
&
MULTI_ARG_CONFIG
)
&&
argc
!=
2
)
{
err
=
"wrong number of arguments"
;
goto
loaderr
;
}
/* Set config using all arguments that follows */
if
(
!
config
->
interface
.
set
(
config
,
&
argv
[
1
],
argc
-
1
,
&
err
))
{
goto
loaderr
;
}
}
/* If there's no matching above, we try matching them with deprecated configs */
if
(
!
match
)
{
sdsfreesplitres
(
argv
,
argc
);
continue
;
}
else
{
int
match
=
0
;
for
(
deprecatedConfig
*
config
=
deprecated_configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
(
!
strcasecmp
(
argv
[
0
],
config
->
name
)
&&
config
->
argc_min
<=
argc
&&
...
...
@@ -490,11 +469,10 @@ void loadServerConfigFromString(char *config) {
break
;
}
}
}
if
(
match
)
{
sdsfreesplitres
(
argv
,
argc
);
continue
;
if
(
match
)
{
sdsfreesplitres
(
argv
,
argc
);
continue
;
}
}
/* Execute config directives */
...
...
@@ -535,6 +513,13 @@ void loadServerConfigFromString(char *config) {
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"loadmodule"
)
&&
argc
>=
2
)
{
queueLoadModule
(
argv
[
1
],
&
argv
[
2
],
argc
-
2
);
}
else
if
(
strchr
(
argv
[
0
],
'.'
))
{
if
(
argc
!=
2
)
{
err
=
"Module config specified without value"
;
goto
loaderr
;
}
sds
name
=
sdsdup
(
argv
[
0
]);
if
(
!
dictReplace
(
server
.
module_configs_queue
,
name
,
sdsdup
(
argv
[
1
])))
sdsfree
(
name
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"sentinel"
))
{
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
...
...
@@ -597,9 +582,10 @@ loaderr:
* Both filename and options can be NULL, in such a case are considered
* empty. This way loadServerConfig can be used to just load a file or
* just load a string. */
#define CONFIG_READ_LEN 1024
void
loadServerConfig
(
char
*
filename
,
char
config_from_stdin
,
char
*
options
)
{
sds
config
=
sdsempty
();
char
buf
[
CONFIG_
MAX_LINE
+
1
];
char
buf
[
CONFIG_
READ_LEN
+
1
];
FILE
*
fp
;
glob_t
globbuf
;
...
...
@@ -631,7 +617,7 @@ void loadServerConfig(char *filename, char config_from_stdin, char *options) {
globbuf
.
gl_pathv
[
i
],
strerror
(
errno
));
exit
(
1
);
}
while
(
fgets
(
buf
,
CONFIG_
MAX_LINE
+
1
,
fp
)
!=
NULL
)
while
(
fgets
(
buf
,
CONFIG_
READ_LEN
+
1
,
fp
)
!=
NULL
)
config
=
sdscat
(
config
,
buf
);
fclose
(
fp
);
}
...
...
@@ -647,7 +633,7 @@ void loadServerConfig(char *filename, char config_from_stdin, char *options) {
filename
,
strerror
(
errno
));
exit
(
1
);
}
while
(
fgets
(
buf
,
CONFIG_
MAX_LINE
+
1
,
fp
)
!=
NULL
)
while
(
fgets
(
buf
,
CONFIG_
READ_LEN
+
1
,
fp
)
!=
NULL
)
config
=
sdscat
(
config
,
buf
);
fclose
(
fp
);
}
...
...
@@ -657,7 +643,7 @@ void loadServerConfig(char *filename, char config_from_stdin, char *options) {
if
(
config_from_stdin
)
{
serverLog
(
LL_WARNING
,
"Reading config from stdin"
);
fp
=
stdin
;
while
(
fgets
(
buf
,
CONFIG_
MAX_LINE
+
1
,
fp
)
!=
NULL
)
while
(
fgets
(
buf
,
CONFIG_
READ_LEN
+
1
,
fp
)
!=
NULL
)
config
=
sdscat
(
config
,
buf
);
}
...
...
@@ -682,12 +668,45 @@ static int performInterfaceSet(standardConfig *config, sds value, const char **e
}
/* Set the config */
res
=
config
->
interface
.
set
(
config
->
data
,
argv
,
argc
,
errstr
);
res
=
config
->
interface
.
set
(
config
,
argv
,
argc
,
errstr
);
if
(
config
->
flags
&
MULTI_ARG_CONFIG
)
sdsfreesplitres
(
argv
,
argc
);
return
res
;
}
static
void
restoreBackupConfig
(
standardConfig
**
set_configs
,
sds
*
old_values
,
int
count
,
apply_fn
*
apply_fns
)
{
/* Find the config by name and attempt to set it to value. */
int
performModuleConfigSetFromName
(
sds
name
,
sds
value
,
const
char
**
err
)
{
standardConfig
*
config
=
lookupConfig
(
name
);
if
(
!
config
||
!
(
config
->
flags
&
MODULE_CONFIG
))
{
*
err
=
"Config name not found"
;
return
0
;
}
return
performInterfaceSet
(
config
,
value
,
err
);
}
/* Find config by name and attempt to set it to its default value. */
int
performModuleConfigSetDefaultFromName
(
sds
name
,
const
char
**
err
)
{
standardConfig
*
config
=
lookupConfig
(
name
);
serverAssert
(
config
);
if
(
!
(
config
->
flags
&
MODULE_CONFIG
))
{
*
err
=
"Config name not found"
;
return
0
;
}
switch
(
config
->
type
)
{
case
BOOL_CONFIG
:
return
setModuleBoolConfig
(
config
->
privdata
,
config
->
data
.
yesno
.
default_value
,
err
);
case
SDS_CONFIG
:
return
setModuleStringConfig
(
config
->
privdata
,
config
->
data
.
sds
.
default_value
,
err
);
case
NUMERIC_CONFIG
:
return
setModuleNumericConfig
(
config
->
privdata
,
config
->
data
.
numeric
.
default_value
,
err
);
case
ENUM_CONFIG
:
return
setModuleEnumConfig
(
config
->
privdata
,
config
->
data
.
enumd
.
default_value
,
err
);
default:
serverPanic
(
"Config type of module config is not allowed."
);
}
return
0
;
}
static
void
restoreBackupConfig
(
standardConfig
**
set_configs
,
sds
*
old_values
,
int
count
,
apply_fn
*
apply_fns
,
list
*
module_configs
)
{
int
i
;
const
char
*
errstr
=
"unknown error"
;
/* Set all backup values */
...
...
@@ -703,6 +722,10 @@ static void restoreBackupConfig(standardConfig **set_configs, sds *old_values, i
serverLog
(
LL_WARNING
,
"Failed applying restored failed CONFIG SET command: %s"
,
errstr
);
}
}
if
(
module_configs
)
{
if
(
!
moduleConfigApplyConfig
(
module_configs
,
&
errstr
,
NULL
))
serverLog
(
LL_WARNING
,
"Failed applying restored failed CONFIG SET command: %s"
,
errstr
);
}
}
/*-----------------------------------------------------------------------------
...
...
@@ -714,6 +737,8 @@ void configSetCommand(client *c) {
const
char
*
invalid_arg_name
=
NULL
;
const
char
*
err_arg_name
=
NULL
;
standardConfig
**
set_configs
;
/* TODO: make this a dict for better performance */
list
*
module_configs_apply
;
const
char
**
config_names
;
sds
*
new_values
;
sds
*
old_values
=
NULL
;
apply_fn
*
apply_fns
;
/* TODO: make this a set for better performance */
...
...
@@ -728,7 +753,9 @@ void configSetCommand(client *c) {
}
config_count
=
(
c
->
argc
-
2
)
/
2
;
module_configs_apply
=
listCreate
();
set_configs
=
zcalloc
(
sizeof
(
standardConfig
*
)
*
config_count
);
config_names
=
zcalloc
(
sizeof
(
char
*
)
*
config_count
);
new_values
=
zmalloc
(
sizeof
(
sds
*
)
*
config_count
);
old_values
=
zcalloc
(
sizeof
(
sds
*
)
*
config_count
);
apply_fns
=
zcalloc
(
sizeof
(
apply_fn
)
*
config_count
);
...
...
@@ -736,73 +763,76 @@ void configSetCommand(client *c) {
/* Find all relevant configs */
for
(
i
=
0
;
i
<
config_count
;
i
++
)
{
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
((
!
strcasecmp
(
c
->
argv
[
2
+
i
*
2
]
->
ptr
,
config
->
name
)
||
(
config
->
alias
&&
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
config
->
alias
))))
{
/* Note: it's important we run over ALL passed configs and check if we need to call `redactClientCommandArgument()`.
* This is in order to avoid anyone using this command for a log/slowlog/monitor/etc. displaying sensitive info.
* So even if we encounter an error we still continue running over the remaining arguments. */
if
(
config
->
flags
&
SENSITIVE_CONFIG
)
{
redactClientCommandArgument
(
c
,
2
+
i
*
2
+
1
);
}
standardConfig
*
config
=
lookupConfig
(
c
->
argv
[
2
+
i
*
2
]
->
ptr
);
/* Fail if we couldn't find this config */
if
(
!
config
)
{
if
(
!
invalid_args
)
{
invalid_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
invalid_args
=
1
;
}
continue
;
}
if
(
!
invalid_args
)
{
if
(
config
->
flags
&
IMMUTABLE_CONFIG
||
(
config
->
flags
&
PROTECTED_CONFIG
&&
!
allowProtectedAction
(
server
.
enable_protected_configs
,
c
)))
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
errstr
=
(
config
->
flags
&
IMMUTABLE_CONFIG
)
?
"can't set immutable config"
:
"can't set protected config"
;
err_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
invalid_args
=
1
;
}
/* Note: it's important we run over ALL passed configs and check if we need to call `redactClientCommandArgument()`.
* This is in order to avoid anyone using this command for a log/slowlog/monitor/etc. displaying sensitive info.
* So even if we encounter an error we still continue running over the remaining arguments. */
if
(
config
->
flags
&
SENSITIVE_CONFIG
)
{
redactClientCommandArgument
(
c
,
2
+
i
*
2
+
1
);
}
if
(
server
.
loading
&&
config
->
flags
&
DENY_LOADING_CONFIG
)
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
deny_loading_error
=
1
;
invalid_args
=
1
;
}
/* We continue to make sure we redact all the configs */
if
(
invalid_args
)
continue
;
/* If this config appears twice then fail */
for
(
j
=
0
;
j
<
i
;
j
++
)
{
if
(
set_configs
[
j
]
==
config
)
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
errstr
=
"duplicate parameter"
;
err_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
invalid_args
=
1
;
break
;
}
}
set_configs
[
i
]
=
config
;
new_values
[
i
]
=
c
->
argv
[
2
+
i
*
2
+
1
]
->
ptr
;
}
break
;
}
if
(
config
->
flags
&
IMMUTABLE_CONFIG
||
(
config
->
flags
&
PROTECTED_CONFIG
&&
!
allowProtectedAction
(
server
.
enable_protected_configs
,
c
)))
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
errstr
=
(
config
->
flags
&
IMMUTABLE_CONFIG
)
?
"can't set immutable config"
:
"can't set protected config"
;
err_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
invalid_args
=
1
;
continue
;
}
/* Fail if we couldn't find this config */
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
if
(
!
invalid_args
&&
!
set_configs
[
i
])
{
invalid_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
if
(
server
.
loading
&&
config
->
flags
&
DENY_LOADING_CONFIG
)
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
deny_loading_error
=
1
;
invalid_args
=
1
;
continue
;
}
/* If this config appears twice then fail */
for
(
j
=
0
;
j
<
i
;
j
++
)
{
if
(
set_configs
[
j
]
==
config
)
{
/* Note: we don't abort the loop since we still want to handle redacting sensitive configs (above) */
errstr
=
"duplicate parameter"
;
err_arg_name
=
c
->
argv
[
2
+
i
*
2
]
->
ptr
;
invalid_args
=
1
;
break
;
}
}
set_configs
[
i
]
=
config
;
config_names
[
i
]
=
config
->
name
;
new_values
[
i
]
=
c
->
argv
[
2
+
i
*
2
+
1
]
->
ptr
;
}
if
(
invalid_args
)
goto
err
;
/* Backup old values before setting new ones */
for
(
i
=
0
;
i
<
config_count
;
i
++
)
old_values
[
i
]
=
set_configs
[
i
]
->
interface
.
get
(
set_configs
[
i
]
->
data
);
old_values
[
i
]
=
set_configs
[
i
]
->
interface
.
get
(
set_configs
[
i
]);
/* Set all new values (don't apply yet) */
for
(
i
=
0
;
i
<
config_count
;
i
++
)
{
int
res
=
performInterfaceSet
(
set_configs
[
i
],
new_values
[
i
],
&
errstr
);
if
(
!
res
)
{
restoreBackupConfig
(
set_configs
,
old_values
,
i
+
1
,
NULL
);
restoreBackupConfig
(
set_configs
,
old_values
,
i
+
1
,
NULL
,
NULL
);
err_arg_name
=
set_configs
[
i
]
->
name
;
goto
err
;
}
else
if
(
res
==
1
)
{
/* A new value was set, if this config has an apply function then store it for execution later */
if
(
set_configs
[
i
]
->
interface
.
apply
)
{
if
(
set_configs
[
i
]
->
flags
&
MODULE_CONFIG
)
{
addModuleConfigApply
(
module_configs_apply
,
set_configs
[
i
]
->
privdata
);
}
else
if
(
set_configs
[
i
]
->
interface
.
apply
)
{
/* Check if this apply function is already stored */
int
exists
=
0
;
for
(
j
=
0
;
apply_fns
[
j
]
!=
NULL
&&
j
<=
i
;
j
++
)
{
...
...
@@ -824,11 +854,20 @@ void configSetCommand(client *c) {
for
(
i
=
0
;
i
<
config_count
&&
apply_fns
[
i
]
!=
NULL
;
i
++
)
{
if
(
!
apply_fns
[
i
](
&
errstr
))
{
serverLog
(
LL_WARNING
,
"Failed applying new configuration. Possibly related to new %s setting. Restoring previous settings."
,
set_configs
[
config_map_fns
[
i
]]
->
name
);
restoreBackupConfig
(
set_configs
,
old_values
,
config_count
,
apply_fns
);
restoreBackupConfig
(
set_configs
,
old_values
,
config_count
,
apply_fns
,
NULL
);
err_arg_name
=
set_configs
[
config_map_fns
[
i
]]
->
name
;
goto
err
;
}
}
/* Apply all module configs that were set. */
if
(
!
moduleConfigApplyConfig
(
module_configs_apply
,
&
errstr
,
&
err_arg_name
))
{
serverLogRaw
(
LL_WARNING
,
"Failed applying new module configuration. Restoring previous settings."
);
restoreBackupConfig
(
set_configs
,
old_values
,
config_count
,
apply_fns
,
module_configs_apply
);
goto
err
;
}
RedisModuleConfigChangeV1
cc
=
{.
num_changes
=
config_count
,
.
config_names
=
config_names
};
moduleFireServerEvent
(
REDISMODULE_EVENT_CONFIG
,
REDISMODULE_SUBEVENT_CONFIG_CHANGE
,
&
cc
);
addReply
(
c
,
shared
.
ok
);
goto
end
;
...
...
@@ -845,12 +884,14 @@ err:
}
end:
zfree
(
set_configs
);
zfree
(
config_names
);
zfree
(
new_values
);
for
(
i
=
0
;
i
<
config_count
;
i
++
)
sdsfree
(
old_values
[
i
]);
zfree
(
old_values
);
zfree
(
apply_fns
);
zfree
(
config_map_fns
);
listRelease
(
module_configs_apply
);
}
/*-----------------------------------------------------------------------------
...
...
@@ -858,38 +899,51 @@ end:
*----------------------------------------------------------------------------*/
void
configGetCommand
(
client
*
c
)
{
void
*
replylen
=
addReplyDeferredLen
(
c
);
int
matches
=
0
;
int
i
;
dictEntry
*
de
;
dictIterator
*
di
;
/* Create a dictionary to store the matched configs */
dict
*
matches
=
dictCreate
(
&
externalStringType
);
for
(
i
=
0
;
i
<
c
->
argc
-
2
;
i
++
)
{
robj
*
o
=
c
->
argv
[
2
+
i
];
sds
name
=
o
->
ptr
;
/* If the string doesn't contain glob patterns, just directly
* look up the key in the dictionary. */
if
(
!
strpbrk
(
name
,
"[*?"
))
{
if
(
dictFind
(
matches
,
name
))
continue
;
standardConfig
*
config
=
lookupConfig
(
name
);
if
(
config
)
{
dictAdd
(
matches
,
name
,
config
);
}
continue
;
}
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
int
matched_conf
=
0
;
int
matched_alias
=
0
;
for
(
i
=
0
;
i
<
c
->
argc
-
2
&&
(
!
matched_conf
||
!
matched_alias
);
i
++
)
{
robj
*
o
=
c
->
argv
[
2
+
i
];
char
*
pattern
=
o
->
ptr
;
/* Otherwise, do a match against all items in the dictionary. */
di
=
dictGetIterator
(
configs
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
standardConfig
*
config
=
dictGetVal
(
de
);
/* Note that hidden configs require an exact match (not a pattern) */
if
(
!
matched_conf
&&
(((
config
->
flags
&
HIDDEN_CONFIG
)
&&
!
strcasecmp
(
pattern
,
config
->
name
))
||
(
!
(
config
->
flags
&
HIDDEN_CONFIG
)
&&
stringmatch
(
pattern
,
config
->
name
,
1
))))
{
addReplyBulkCString
(
c
,
config
->
name
);
addReplyBulkSds
(
c
,
config
->
interface
.
get
(
config
->
data
));
matches
++
;
matched_conf
=
1
;
}
if
(
!
matched_alias
&&
config
->
alias
&&
(((
config
->
flags
&
HIDDEN_CONFIG
)
&&
!
strcasecmp
(
pattern
,
config
->
alias
))
||
(
!
(
config
->
flags
&
HIDDEN_CONFIG
)
&&
stringmatch
(
pattern
,
config
->
alias
,
1
))))
{
addReplyBulkCString
(
c
,
config
->
alias
);
addReplyBulkSds
(
c
,
config
->
interface
.
get
(
config
->
data
));
matches
++
;
matched_alias
=
1
;
if
(
config
->
flags
&
HIDDEN_CONFIG
)
continue
;
if
(
dictFind
(
matches
,
config
->
name
))
continue
;
if
(
stringmatch
(
name
,
de
->
key
,
1
))
{
dictAdd
(
matches
,
de
->
key
,
config
);
}
}
dictReleaseIterator
(
di
);
}
setDeferredMapLen
(
c
,
replylen
,
matches
);
di
=
dictGetIterator
(
matches
);
addReplyMapLen
(
c
,
dictSize
(
matches
));
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
standardConfig
*
config
=
(
standardConfig
*
)
dictGetVal
(
de
);
addReplyBulkCString
(
c
,
de
->
key
);
addReplyBulkSds
(
c
,
config
->
interface
.
get
(
config
));
}
dictReleaseIterator
(
di
);
dictRelease
(
matches
);
}
/*-----------------------------------------------------------------------------
...
...
@@ -996,17 +1050,32 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
FILE
*
fp
=
fopen
(
path
,
"r"
);
if
(
fp
==
NULL
&&
errno
!=
ENOENT
)
return
NULL
;
char
buf
[
CONFIG_MAX_LINE
+
1
];
struct
redis_stat
sb
;
if
(
fp
&&
redis_fstat
(
fileno
(
fp
),
&
sb
)
==
-
1
)
return
NULL
;
int
linenum
=
-
1
;
struct
rewriteConfigState
*
state
=
rewriteConfigCreateState
();
if
(
fp
==
NULL
)
return
state
;
if
(
fp
==
NULL
||
sb
.
st_size
==
0
)
return
state
;
/* Read the old file line by line, populate the state. */
while
(
fgets
(
buf
,
CONFIG_MAX_LINE
+
1
,
fp
)
!=
NULL
)
{
/* Load the file content */
sds
config
=
sdsnewlen
(
SDS_NOINIT
,
sb
.
st_size
);
if
(
fread
(
config
,
1
,
sb
.
st_size
,
fp
)
==
0
)
{
sdsfree
(
config
);
rewriteConfigReleaseState
(
state
);
fclose
(
fp
);
return
NULL
;
}
int
i
,
totlines
;
sds
*
lines
=
sdssplitlen
(
config
,
sdslen
(
config
),
"
\n
"
,
1
,
&
totlines
);
/* Read the old content line by line, populate the state. */
for
(
i
=
0
;
i
<
totlines
;
i
++
)
{
int
argc
;
sds
*
argv
;
sds
line
=
sdstrim
(
sdsnew
(
buf
),
"
\r\n\t
"
);
sds
line
=
sdstrim
(
lines
[
i
],
"
\r\n\t
"
);
lines
[
i
]
=
NULL
;
linenum
++
;
/* Zero based, so we init at -1 */
...
...
@@ -1020,12 +1089,13 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
/* Not a comment, split into arguments. */
argv
=
sdssplitargs
(
line
,
&
argc
);
if
(
argv
==
NULL
)
{
if
(
argv
==
NULL
||
(
!
server
.
sentinel_mode
&&
!
lookupConfig
(
argv
[
0
]))
)
{
/* Apparently the line is unparsable for some reason, for
* instance it may have unbalanced quotes
. Load it as
a
* comment. */
* instance it may have unbalanced quotes
, or may contain
a
*
config that doesn't exist anymore. Load it as a
comment. */
sds
aux
=
sdsnew
(
"# ??? "
);
aux
=
sdscatsds
(
aux
,
line
);
if
(
argv
)
sdsfreesplitres
(
argv
,
argc
);
sdsfree
(
line
);
rewriteConfigAppendLine
(
state
,
aux
);
continue
;
...
...
@@ -1062,6 +1132,8 @@ struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {
sdsfreesplitres
(
argv
,
argc
);
}
fclose
(
fp
);
sdsfreesplitres
(
lines
,
totlines
);
sdsfree
(
config
);
return
state
;
}
...
...
@@ -1235,8 +1307,8 @@ void rewriteConfigEnumOption(struct rewriteConfigState *state, const char *optio
}
/* Rewrite the save option. */
void
rewriteConfigSaveOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigSaveOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
int
j
;
sds
line
;
...
...
@@ -1296,8 +1368,8 @@ void rewriteConfigUserOption(struct rewriteConfigState *state) {
}
/* Rewrite the dir option, always using absolute paths.*/
void
rewriteConfigDirOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigDirOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
char
cwd
[
1024
];
if
(
getcwd
(
cwd
,
sizeof
(
cwd
))
==
NULL
)
{
...
...
@@ -1308,8 +1380,8 @@ void rewriteConfigDirOption(typeData data, const char *name, struct rewriteConfi
}
/* Rewrite the slaveof option. */
void
rewriteConfigReplicaOfOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigReplicaOfOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
sds
line
;
/* If this is a master, we want all the slaveof config options
...
...
@@ -1325,8 +1397,8 @@ void rewriteConfigReplicaOfOption(typeData data, const char *name, struct rewrit
}
/* Rewrite the notify-keyspace-events option. */
void
rewriteConfigNotifyKeyspaceEventsOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigNotifyKeyspaceEventsOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
int
force
=
server
.
notify_keyspace_events
!=
0
;
sds
line
,
flags
;
...
...
@@ -1339,8 +1411,8 @@ void rewriteConfigNotifyKeyspaceEventsOption(typeData data, const char *name, st
}
/* Rewrite the client-output-buffer-limit option. */
void
rewriteConfigClientOutputBufferLimitOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigClientOutputBufferLimitOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
int
j
;
for
(
j
=
0
;
j
<
CLIENT_TYPE_OBUF_COUNT
;
j
++
)
{
int
force
=
(
server
.
client_obuf_limits
[
j
].
hard_limit_bytes
!=
...
...
@@ -1367,8 +1439,8 @@ void rewriteConfigClientOutputBufferLimitOption(typeData data, const char *name,
}
/* Rewrite the oom-score-adj-values option. */
void
rewriteConfigOOMScoreAdjValuesOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigOOMScoreAdjValuesOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
int
force
=
0
;
int
j
;
sds
line
;
...
...
@@ -1387,8 +1459,8 @@ void rewriteConfigOOMScoreAdjValuesOption(typeData data, const char *name, struc
}
/* Rewrite the bind option. */
void
rewriteConfigBindOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigBindOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
int
force
=
1
;
sds
line
,
addresses
;
int
is_default
=
0
;
...
...
@@ -1508,10 +1580,14 @@ sds getConfigDebugInfo() {
/* Iterate the configs and "rewrite" the ones that have
* the debug flag. */
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
dictIterator
*
di
=
dictGetIterator
(
configs
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
standardConfig
*
config
=
dictGetVal
(
de
);
if
(
!
(
config
->
flags
&
DEBUG_CONFIG
))
continue
;
config
->
interface
.
rewrite
(
config
->
data
,
config
->
name
,
state
);
config
->
interface
.
rewrite
(
config
,
config
->
name
,
state
);
}
dictReleaseIterator
(
di
);
sds
info
=
rewriteConfigGetContentFromState
(
state
);
rewriteConfigReleaseState
(
state
);
return
info
;
...
...
@@ -1599,9 +1675,15 @@ int rewriteConfig(char *path, int force_write) {
* the rewrite state. */
/* Iterate the configs that are standard */
for
(
standardConfig
*
config
=
configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
(
config
->
interface
.
rewrite
)
config
->
interface
.
rewrite
(
config
->
data
,
config
->
name
,
state
);
dictIterator
*
di
=
dictGetIterator
(
configs
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
standardConfig
*
config
=
dictGetVal
(
de
);
/* Only rewrite the primary names */
if
(
config
->
flags
&
ALIAS_CONFIG
)
continue
;
if
(
config
->
interface
.
rewrite
)
config
->
interface
.
rewrite
(
config
,
de
->
key
,
state
);
}
dictReleaseIterator
(
di
);
rewriteConfigUserOption
(
state
);
rewriteConfigLoadmoduleOption
(
state
);
...
...
@@ -1656,38 +1738,46 @@ static char loadbuf[LOADBUF_SIZE];
*/
/* Bool Configs */
static
void
boolConfigInit
(
typeData
data
)
{
*
data
.
yesno
.
config
=
data
.
yesno
.
default_value
;
static
void
boolConfigInit
(
standardConfig
*
config
)
{
*
config
->
data
.
yesno
.
config
=
config
->
data
.
yesno
.
default_value
;
}
static
int
boolConfigSet
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
boolConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
int
yn
=
yesnotoi
(
argv
[
0
]);
if
(
yn
==
-
1
)
{
*
err
=
"argument must be 'yes' or 'no'"
;
return
0
;
}
if
(
data
.
yesno
.
is_valid_fn
&&
!
data
.
yesno
.
is_valid_fn
(
yn
,
err
))
if
(
config
->
data
.
yesno
.
is_valid_fn
&&
!
config
->
data
.
yesno
.
is_valid_fn
(
yn
,
err
))
return
0
;
int
prev
=
*
(
data
.
yesno
.
config
);
int
prev
=
config
->
flags
&
MODULE_CONFIG
?
getModuleBoolConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
yesno
.
config
);
if
(
prev
!=
yn
)
{
*
(
data
.
yesno
.
config
)
=
yn
;
if
(
config
->
flags
&
MODULE_CONFIG
)
{
return
setModuleBoolConfig
(
config
->
privdata
,
yn
,
err
);
}
*
(
config
->
data
.
yesno
.
config
)
=
yn
;
return
1
;
}
return
2
;
}
static
sds
boolConfigGet
(
typeData
data
)
{
return
sdsnew
(
*
data
.
yesno
.
config
?
"yes"
:
"no"
);
static
sds
boolConfigGet
(
standardConfig
*
config
)
{
if
(
config
->
flags
&
MODULE_CONFIG
)
{
return
sdsnew
(
getModuleBoolConfig
(
config
->
privdata
)
?
"yes"
:
"no"
);
}
return
sdsnew
(
*
config
->
data
.
yesno
.
config
?
"yes"
:
"no"
);
}
static
void
boolConfigRewrite
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
rewriteConfigYesNoOption
(
state
,
name
,
*
(
data
.
yesno
.
config
),
data
.
yesno
.
default_value
);
static
void
boolConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
int
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleBoolConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
yesno
.
config
);
rewriteConfigYesNoOption
(
state
,
name
,
val
,
config
->
data
.
yesno
.
default_value
);
}
#define createBoolConfig(name, alias, flags, config_addr, default, is_valid, apply) { \
embedCommonConfig(name, alias, flags) \
embedConfigInterface(boolConfigInit, boolConfigSet, boolConfigGet, boolConfigRewrite, apply) \
.type = BOOL_CONFIG, \
.data.yesno = { \
.config = &(config_addr), \
.default_value = (default), \
...
...
@@ -1696,61 +1786,69 @@ static void boolConfigRewrite(typeData data, const char *name, struct rewriteCon
}
/* String Configs */
static
void
stringConfigInit
(
typeData
data
)
{
*
data
.
string
.
config
=
(
data
.
string
.
convert_empty_to_null
&&
!
data
.
string
.
default_value
)
?
NULL
:
zstrdup
(
data
.
string
.
default_value
);
static
void
stringConfigInit
(
standardConfig
*
config
)
{
*
config
->
data
.
string
.
config
=
(
config
->
data
.
string
.
convert_empty_to_null
&&
!
config
->
data
.
string
.
default_value
)
?
NULL
:
zstrdup
(
config
->
data
.
string
.
default_value
);
}
static
int
stringConfigSet
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
stringConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
if
(
data
.
string
.
is_valid_fn
&&
!
data
.
string
.
is_valid_fn
(
argv
[
0
],
err
))
if
(
config
->
data
.
string
.
is_valid_fn
&&
!
config
->
data
.
string
.
is_valid_fn
(
argv
[
0
],
err
))
return
0
;
char
*
prev
=
*
data
.
string
.
config
;
char
*
new
=
(
data
.
string
.
convert_empty_to_null
&&
!
argv
[
0
][
0
])
?
NULL
:
argv
[
0
];
char
*
prev
=
*
config
->
data
.
string
.
config
;
char
*
new
=
(
config
->
data
.
string
.
convert_empty_to_null
&&
!
argv
[
0
][
0
])
?
NULL
:
argv
[
0
];
if
(
new
!=
prev
&&
(
new
==
NULL
||
prev
==
NULL
||
strcmp
(
prev
,
new
)))
{
*
data
.
string
.
config
=
new
!=
NULL
?
zstrdup
(
new
)
:
NULL
;
*
config
->
data
.
string
.
config
=
new
!=
NULL
?
zstrdup
(
new
)
:
NULL
;
zfree
(
prev
);
return
1
;
}
return
2
;
}
static
sds
stringConfigGet
(
typeData
data
)
{
return
sdsnew
(
*
data
.
string
.
config
?
*
data
.
string
.
config
:
""
);
static
sds
stringConfigGet
(
standardConfig
*
config
)
{
return
sdsnew
(
*
config
->
data
.
string
.
config
?
*
config
->
data
.
string
.
config
:
""
);
}
static
void
stringConfigRewrite
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
rewriteConfigStringOption
(
state
,
name
,
*
(
data
.
string
.
config
),
data
.
string
.
default_value
);
static
void
stringConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
rewriteConfigStringOption
(
state
,
name
,
*
(
config
->
data
.
string
.
config
),
config
->
data
.
string
.
default_value
);
}
/* SDS Configs */
static
void
sdsConfigInit
(
typeData
data
)
{
*
data
.
sds
.
config
=
(
data
.
sds
.
convert_empty_to_null
&&
!
data
.
sds
.
default_value
)
?
NULL
:
sdsnew
(
data
.
sds
.
default_value
);
static
void
sdsConfigInit
(
standardConfig
*
config
)
{
*
config
->
data
.
sds
.
config
=
(
config
->
data
.
sds
.
convert_empty_to_null
&&
!
config
->
data
.
sds
.
default_value
)
?
NULL
:
sdsnew
(
config
->
data
.
sds
.
default_value
);
}
static
int
sdsConfigSet
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
sdsConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
if
(
data
.
sds
.
is_valid_fn
&&
!
data
.
sds
.
is_valid_fn
(
argv
[
0
],
err
))
if
(
config
->
data
.
sds
.
is_valid_fn
&&
!
config
->
data
.
sds
.
is_valid_fn
(
argv
[
0
],
err
))
return
0
;
sds
prev
=
*
data
.
sds
.
config
;
sds
new
=
(
data
.
string
.
convert_empty_to_null
&&
(
sdslen
(
argv
[
0
])
==
0
))
?
NULL
:
argv
[
0
];
sds
prev
=
config
->
flags
&
MODULE_CONFIG
?
getModuleStringConfig
(
config
->
privdata
)
:
*
config
->
data
.
sds
.
config
;
sds
new
=
(
config
->
data
.
string
.
convert_empty_to_null
&&
(
sdslen
(
argv
[
0
])
==
0
))
?
NULL
:
argv
[
0
];
if
(
new
!=
prev
&&
(
new
==
NULL
||
prev
==
NULL
||
sdscmp
(
prev
,
new
)))
{
*
data
.
sds
.
config
=
new
!=
NULL
?
sdsdup
(
new
)
:
NULL
;
sdsfree
(
prev
);
if
(
config
->
flags
&
MODULE_CONFIG
)
{
return
setModuleStringConfig
(
config
->
privdata
,
new
,
err
);
}
*
config
->
data
.
sds
.
config
=
new
!=
NULL
?
sdsdup
(
new
)
:
NULL
;
return
1
;
}
if
(
config
->
flags
&
MODULE_CONFIG
&&
prev
)
sdsfree
(
prev
);
return
2
;
}
static
sds
sdsConfigGet
(
typeData
data
)
{
if
(
*
data
.
sds
.
config
)
{
return
sdsdup
(
*
data
.
sds
.
config
);
static
sds
sdsConfigGet
(
standardConfig
*
config
)
{
sds
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleStringConfig
(
config
->
privdata
)
:
*
config
->
data
.
sds
.
config
;
if
(
val
)
{
if
(
config
->
flags
&
MODULE_CONFIG
)
return
val
;
return
sdsdup
(
val
);
}
else
{
return
sdsnew
(
""
);
}
}
static
void
sdsConfigRewrite
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
rewriteConfigSdsOption
(
state
,
name
,
*
(
data
.
sds
.
config
),
data
.
sds
.
default_value
);
static
void
sdsConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
sds
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleStringConfig
(
config
->
privdata
)
:
*
config
->
data
.
sds
.
config
;
rewriteConfigSdsOption
(
state
,
name
,
val
,
config
->
data
.
sds
.
default_value
);
if
(
val
)
sdsfree
(
val
);
}
...
...
@@ -1760,6 +1858,7 @@ static void sdsConfigRewrite(typeData data, const char *name, struct rewriteConf
#define createStringConfig(name, alias, flags, empty_to_null, config_addr, default, is_valid, apply) { \
embedCommonConfig(name, alias, flags) \
embedConfigInterface(stringConfigInit, stringConfigSet, stringConfigGet, stringConfigRewrite, apply) \
.type = STRING_CONFIG, \
.data.string = { \
.config = &(config_addr), \
.default_value = (default), \
...
...
@@ -1771,6 +1870,7 @@ static void sdsConfigRewrite(typeData data, const char *name, struct rewriteConf
#define createSDSConfig(name, alias, flags, empty_to_null, config_addr, default, is_valid, apply) { \
embedCommonConfig(name, alias, flags) \
embedConfigInterface(sdsConfigInit, sdsConfigSet, sdsConfigGet, sdsConfigRewrite, apply) \
.type = SDS_CONFIG, \
.data.sds = { \
.config = &(config_addr), \
.default_value = (default), \
...
...
@@ -1780,16 +1880,16 @@ static void sdsConfigRewrite(typeData data, const char *name, struct rewriteConf
}
/* Enum configs */
static
void
enumConfigInit
(
typeData
data
)
{
*
data
.
enumd
.
config
=
data
.
enumd
.
default_value
;
static
void
enumConfigInit
(
standardConfig
*
config
)
{
*
config
->
data
.
enumd
.
config
=
config
->
data
.
enumd
.
default_value
;
}
static
int
enumConfigSet
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
enumConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
int
enumval
=
configEnumGetValue
(
data
.
enumd
.
enum_value
,
argv
[
0
]);
int
enumval
=
configEnumGetValue
(
config
->
data
.
enumd
.
enum_value
,
argv
[
0
]);
if
(
enumval
==
INT_MIN
)
{
sds
enumerr
=
sdsnew
(
"argument must be one of the following: "
);
configEnum
*
enumNode
=
data
.
enumd
.
enum_value
;
configEnum
*
enumNode
=
config
->
data
.
enumd
.
enum_value
;
while
(
enumNode
->
name
!=
NULL
)
{
enumerr
=
sdscatlen
(
enumerr
,
enumNode
->
name
,
strlen
(
enumNode
->
name
));
...
...
@@ -1805,27 +1905,32 @@ static int enumConfigSet(typeData data, sds *argv, int argc, const char **err) {
*
err
=
loadbuf
;
return
0
;
}
if
(
data
.
enumd
.
is_valid_fn
&&
!
data
.
enumd
.
is_valid_fn
(
enumval
,
err
))
if
(
config
->
data
.
enumd
.
is_valid_fn
&&
!
config
->
data
.
enumd
.
is_valid_fn
(
enumval
,
err
))
return
0
;
int
prev
=
*
(
data
.
enumd
.
config
);
int
prev
=
config
->
flags
&
MODULE_CONFIG
?
getModuleEnumConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
enumd
.
config
);
if
(
prev
!=
enumval
)
{
*
(
data
.
enumd
.
config
)
=
enumval
;
if
(
config
->
flags
&
MODULE_CONFIG
)
return
setModuleEnumConfig
(
config
->
privdata
,
enumval
,
err
);
*
(
config
->
data
.
enumd
.
config
)
=
enumval
;
return
1
;
}
return
2
;
}
static
sds
enumConfigGet
(
typeData
data
)
{
return
sdsnew
(
configEnumGetNameOrUnknown
(
data
.
enumd
.
enum_value
,
*
data
.
enumd
.
config
));
static
sds
enumConfigGet
(
standardConfig
*
config
)
{
int
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleEnumConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
enumd
.
config
);
return
sdsnew
(
configEnumGetNameOrUnknown
(
config
->
data
.
enumd
.
enum_value
,
val
));
}
static
void
enumConfigRewrite
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
rewriteConfigEnumOption
(
state
,
name
,
*
(
data
.
enumd
.
config
),
data
.
enumd
.
enum_value
,
data
.
enumd
.
default_value
);
static
void
enumConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
int
val
=
config
->
flags
&
MODULE_CONFIG
?
getModuleEnumConfig
(
config
->
privdata
)
:
*
(
config
->
data
.
enumd
.
config
);
rewriteConfigEnumOption
(
state
,
name
,
val
,
config
->
data
.
enumd
.
enum_value
,
config
->
data
.
enumd
.
default_value
);
}
#define createEnumConfig(name, alias, flags, enum, config_addr, default, is_valid, apply) { \
embedCommonConfig(name, alias, flags) \
embedConfigInterface(enumConfigInit, enumConfigSet, enumConfigGet, enumConfigRewrite, apply) \
.type = ENUM_CONFIG, \
.data.enumd = { \
.config = &(config_addr), \
.default_value = (default), \
...
...
@@ -1836,69 +1941,74 @@ static void enumConfigRewrite(typeData data, const char *name, struct rewriteCon
/* Gets a 'long long val' and sets it into the union, using a macro to get
* compile time type check. */
#define SET_NUMERIC_TYPE(val) \
if (data.numeric.numeric_type == NUMERIC_TYPE_INT) { \
*(data.numeric.config.i) = (int) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_UINT) { \
*(data.numeric.config.ui) = (unsigned int) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_LONG) { \
*(data.numeric.config.l) = (long) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_ULONG) { \
*(data.numeric.config.ul) = (unsigned long) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_LONG_LONG) { \
*(data.numeric.config.ll) = (long long) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_ULONG_LONG) { \
*(data.numeric.config.ull) = (unsigned long long) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_SIZE_T) { \
*(data.numeric.config.st) = (size_t) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_SSIZE_T) { \
*(data.numeric.config.sst) = (ssize_t) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_OFF_T) { \
*(data.numeric.config.ot) = (off_t) val; \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_TIME_T) { \
*(data.numeric.config.tt) = (time_t) val; \
int
setNumericType
(
standardConfig
*
config
,
long
long
val
,
const
char
**
err
)
{
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_INT
)
{
*
(
config
->
data
.
numeric
.
config
.
i
)
=
(
int
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_UINT
)
{
*
(
config
->
data
.
numeric
.
config
.
ui
)
=
(
unsigned
int
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_LONG
)
{
*
(
config
->
data
.
numeric
.
config
.
l
)
=
(
long
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG
)
{
*
(
config
->
data
.
numeric
.
config
.
ul
)
=
(
unsigned
long
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_LONG_LONG
)
{
if
(
config
->
flags
&
MODULE_CONFIG
)
return
setModuleNumericConfig
(
config
->
privdata
,
val
,
err
);
else
*
(
config
->
data
.
numeric
.
config
.
ll
)
=
(
long
long
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG_LONG
)
{
*
(
config
->
data
.
numeric
.
config
.
ull
)
=
(
unsigned
long
long
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SIZE_T
)
{
*
(
config
->
data
.
numeric
.
config
.
st
)
=
(
size_t
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SSIZE_T
)
{
*
(
config
->
data
.
numeric
.
config
.
sst
)
=
(
ssize_t
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_OFF_T
)
{
*
(
config
->
data
.
numeric
.
config
.
ot
)
=
(
off_t
)
val
;
}
else
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_TIME_T
)
{
*
(
config
->
data
.
numeric
.
config
.
tt
)
=
(
time_t
)
val
;
}
return
1
;
}
/* Gets a 'long long val' and sets it with the value from the union, using a
* macro to get compile time type check. */
#define GET_NUMERIC_TYPE(val) \
if (data.numeric.numeric_type == NUMERIC_TYPE_INT) { \
val = *(data.numeric.config.i); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_UINT) { \
val = *(data.numeric.config.ui); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_LONG) { \
val = *(data.numeric.config.l); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_ULONG) { \
val = *(data.numeric.config.ul); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_LONG_LONG) { \
val = *(data.numeric.config.ll); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_ULONG_LONG) { \
val = *(data.numeric.config.ull); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_SIZE_T) { \
val = *(data.numeric.config.st); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_SSIZE_T) { \
val = *(data.numeric.config.sst); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_OFF_T) { \
val = *(data.numeric.config.ot); \
} else if (data.numeric.numeric_type == NUMERIC_TYPE_TIME_T) { \
val = *(data.numeric.config.tt); \
if (config->data.numeric.numeric_type == NUMERIC_TYPE_INT) { \
val = *(config->data.numeric.config.i); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_UINT) { \
val = *(config->data.numeric.config.ui); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_LONG) { \
val = *(config->data.numeric.config.l); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_ULONG) { \
val = *(config->data.numeric.config.ul); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_LONG_LONG) { \
if (config->flags & MODULE_CONFIG) val = getModuleNumericConfig(config->privdata); \
else val = *(config->data.numeric.config.ll); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_ULONG_LONG) { \
val = *(config->data.numeric.config.ull); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_SIZE_T) { \
val = *(config->data.numeric.config.st); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_SSIZE_T) { \
val = *(config->data.numeric.config.sst); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_OFF_T) { \
val = *(config->data.numeric.config.ot); \
} else if (config->data.numeric.numeric_type == NUMERIC_TYPE_TIME_T) { \
val = *(config->data.numeric.config.tt); \
}
/* Numeric configs */
static
void
numericConfigInit
(
typeData
data
)
{
SET_NUMERIC_TYPE
(
data
.
numeric
.
default_value
)
static
void
numericConfigInit
(
standardConfig
*
config
)
{
setNumericType
(
config
,
config
->
data
.
numeric
.
default_value
,
NULL
);
}
static
int
numericBoundaryCheck
(
typeData
data
,
long
long
ll
,
const
char
**
err
)
{
if
(
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG_LONG
||
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_UINT
||
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SIZE_T
)
{
static
int
numericBoundaryCheck
(
standardConfig
*
config
,
long
long
ll
,
const
char
**
err
)
{
if
(
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_ULONG_LONG
||
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_UINT
||
config
->
data
.
numeric
.
numeric_type
==
NUMERIC_TYPE_SIZE_T
)
{
/* Boundary check for unsigned types */
unsigned
long
long
ull
=
ll
;
unsigned
long
long
upper_bound
=
data
.
numeric
.
upper_bound
;
unsigned
long
long
lower_bound
=
data
.
numeric
.
lower_bound
;
unsigned
long
long
upper_bound
=
config
->
data
.
numeric
.
upper_bound
;
unsigned
long
long
lower_bound
=
config
->
data
.
numeric
.
lower_bound
;
if
(
ull
>
upper_bound
||
ull
<
lower_bound
)
{
if
(
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
if
(
config
->
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
snprintf
(
loadbuf
,
LOADBUF_SIZE
,
"argument must be between %llo and %llo inclusive"
,
lower_bound
,
...
...
@@ -1914,21 +2024,21 @@ static int numericBoundaryCheck(typeData data, long long ll, const char **err) {
}
}
else
{
/* Boundary check for percentages */
if
(
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
ll
<
0
)
{
if
(
ll
<
data
.
numeric
.
lower_bound
)
{
if
(
config
->
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
ll
<
0
)
{
if
(
ll
<
config
->
data
.
numeric
.
lower_bound
)
{
snprintf
(
loadbuf
,
LOADBUF_SIZE
,
"percentage argument must be less or equal to %lld"
,
-
data
.
numeric
.
lower_bound
);
-
config
->
data
.
numeric
.
lower_bound
);
*
err
=
loadbuf
;
return
0
;
}
}
/* Boundary check for signed types */
else
if
(
ll
>
data
.
numeric
.
upper_bound
||
ll
<
data
.
numeric
.
lower_bound
)
{
else
if
(
ll
>
config
->
data
.
numeric
.
upper_bound
||
ll
<
config
->
data
.
numeric
.
lower_bound
)
{
snprintf
(
loadbuf
,
LOADBUF_SIZE
,
"argument must be between %lld and %lld inclusive"
,
data
.
numeric
.
lower_bound
,
data
.
numeric
.
upper_bound
);
config
->
data
.
numeric
.
lower_bound
,
config
->
data
.
numeric
.
upper_bound
);
*
err
=
loadbuf
;
return
0
;
}
...
...
@@ -1936,9 +2046,9 @@ static int numericBoundaryCheck(typeData data, long long ll, const char **err) {
return
1
;
}
static
int
numericParseString
(
typeData
data
,
sds
value
,
const
char
**
err
,
long
long
*
res
)
{
static
int
numericParseString
(
standardConfig
*
config
,
sds
value
,
const
char
**
err
,
long
long
*
res
)
{
/* First try to parse as memory */
if
(
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
if
(
config
->
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
int
memerr
;
*
res
=
memtoull
(
value
,
&
memerr
);
if
(
!
memerr
)
...
...
@@ -1946,7 +2056,7 @@ static int numericParseString(typeData data, sds value, const char **err, long l
}
/* Attempt to parse as percent */
if
(
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
if
(
config
->
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
sdslen
(
value
)
>
1
&&
value
[
sdslen
(
value
)
-
1
]
==
'%'
&&
string2ll
(
value
,
sdslen
(
value
)
-
1
,
res
)
&&
*
res
>=
0
)
{
...
...
@@ -1956,7 +2066,7 @@ static int numericParseString(typeData data, sds value, const char **err, long l
}
/* Attempt to parse as an octal number */
if
(
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
if
(
config
->
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
char
*
endptr
;
errno
=
0
;
*
res
=
strtoll
(
value
,
&
endptr
,
8
);
...
...
@@ -1965,58 +2075,57 @@ static int numericParseString(typeData data, sds value, const char **err, long l
}
/* Attempt a simple number (no special flags set) */
if
(
!
data
.
numeric
.
flags
&&
string2ll
(
value
,
sdslen
(
value
),
res
))
if
(
!
config
->
data
.
numeric
.
flags
&&
string2ll
(
value
,
sdslen
(
value
),
res
))
return
1
;
/* Select appropriate error string */
if
(
data
.
numeric
.
flags
&
MEMORY_CONFIG
&&
data
.
numeric
.
flags
&
PERCENT_CONFIG
)
if
(
config
->
data
.
numeric
.
flags
&
MEMORY_CONFIG
&&
config
->
data
.
numeric
.
flags
&
PERCENT_CONFIG
)
*
err
=
"argument must be a memory or percent value"
;
else
if
(
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
else
if
(
config
->
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
*
err
=
"argument must be a memory value"
;
else
if
(
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
else
if
(
config
->
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
*
err
=
"argument couldn't be parsed as an octal number"
;
else
*
err
=
"argument couldn't be parsed into an integer"
;
return
0
;
}
static
int
numericConfigSet
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
numericConfigSet
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
argc
);
long
long
ll
,
prev
=
0
;
if
(
!
numericParseString
(
data
,
argv
[
0
],
err
,
&
ll
))
if
(
!
numericParseString
(
config
,
argv
[
0
],
err
,
&
ll
))
return
0
;
if
(
!
numericBoundaryCheck
(
data
,
ll
,
err
))
if
(
!
numericBoundaryCheck
(
config
,
ll
,
err
))
return
0
;
if
(
data
.
numeric
.
is_valid_fn
&&
!
data
.
numeric
.
is_valid_fn
(
ll
,
err
))
if
(
config
->
data
.
numeric
.
is_valid_fn
&&
!
config
->
data
.
numeric
.
is_valid_fn
(
ll
,
err
))
return
0
;
GET_NUMERIC_TYPE
(
prev
)
if
(
prev
!=
ll
)
{
SET_NUMERIC_TYPE
(
ll
)
return
1
;
return
setNumericType
(
config
,
ll
,
err
);
}
return
2
;
}
static
sds
numericConfigGet
(
typeData
data
)
{
static
sds
numericConfigGet
(
standardConfig
*
config
)
{
char
buf
[
128
];
long
long
value
=
0
;
GET_NUMERIC_TYPE
(
value
)
if
(
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
value
<
0
)
{
if
(
config
->
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
value
<
0
)
{
int
len
=
ll2string
(
buf
,
sizeof
(
buf
),
-
value
);
buf
[
len
]
=
'%'
;
buf
[
len
+
1
]
=
'\0'
;
}
else
if
(
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
else
if
(
config
->
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
ull2string
(
buf
,
sizeof
(
buf
),
value
);
}
else
if
(
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
}
else
if
(
config
->
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%llo"
,
value
);
}
else
{
ll2string
(
buf
,
sizeof
(
buf
),
value
);
...
...
@@ -2024,25 +2133,26 @@ static sds numericConfigGet(typeData data) {
return
sdsnew
(
buf
);
}
static
void
numericConfigRewrite
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
static
void
numericConfigRewrite
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
long
long
value
=
0
;
GET_NUMERIC_TYPE
(
value
)
if
(
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
value
<
0
)
{
rewriteConfigPercentOption
(
state
,
name
,
-
value
,
data
.
numeric
.
default_value
);
}
else
if
(
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
rewriteConfigBytesOption
(
state
,
name
,
value
,
data
.
numeric
.
default_value
);
}
else
if
(
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
rewriteConfigOctalOption
(
state
,
name
,
value
,
data
.
numeric
.
default_value
);
if
(
config
->
data
.
numeric
.
flags
&
PERCENT_CONFIG
&&
value
<
0
)
{
rewriteConfigPercentOption
(
state
,
name
,
-
value
,
config
->
data
.
numeric
.
default_value
);
}
else
if
(
config
->
data
.
numeric
.
flags
&
MEMORY_CONFIG
)
{
rewriteConfigBytesOption
(
state
,
name
,
value
,
config
->
data
.
numeric
.
default_value
);
}
else
if
(
config
->
data
.
numeric
.
flags
&
OCTAL_CONFIG
)
{
rewriteConfigOctalOption
(
state
,
name
,
value
,
config
->
data
.
numeric
.
default_value
);
}
else
{
rewriteConfigNumericalOption
(
state
,
name
,
value
,
data
.
numeric
.
default_value
);
rewriteConfigNumericalOption
(
state
,
name
,
value
,
config
->
data
.
numeric
.
default_value
);
}
}
#define embedCommonNumericalConfig(name, alias, _flags, lower, upper, config_addr, default, num_conf_flags, is_valid, apply) { \
embedCommonConfig(name, alias, _flags) \
embedConfigInterface(numericConfigInit, numericConfigSet, numericConfigGet, numericConfigRewrite, apply) \
.type = NUMERIC_CONFIG, \
.data.numeric = { \
.lower_bound = (lower), \
.upper_bound = (upper), \
...
...
@@ -2121,6 +2231,7 @@ static void numericConfigRewrite(typeData data, const char *name, struct rewrite
}
#define createSpecialConfig(name, alias, modifiable, setfn, getfn, rewritefn, applyfn) { \
.type = SPECIAL_CONFIG, \
embedCommonConfig(name, alias, modifiable) \
embedConfigInterface(NULL, setfn, getfn, rewritefn, applyfn) \
}
...
...
@@ -2397,8 +2508,8 @@ static int applyTLSPort(const char **err) {
#endif
/* USE_OPENSSL */
static
int
setConfigDirOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigDirOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
if
(
argc
!=
1
)
{
*
err
=
"wrong number of arguments"
;
return
0
;
...
...
@@ -2410,8 +2521,8 @@ static int setConfigDirOption(typeData data, sds *argv, int argc, const char **e
return
1
;
}
static
sds
getConfigDirOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigDirOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
char
buf
[
1024
];
if
(
getcwd
(
buf
,
sizeof
(
buf
))
==
NULL
)
...
...
@@ -2420,8 +2531,8 @@ static sds getConfigDirOption(typeData data) {
return
sdsnew
(
buf
);
}
static
int
setConfigSaveOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigSaveOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
int
j
;
/* Special case: treat single arg "" as zero args indicating empty save configuration */
...
...
@@ -2473,8 +2584,8 @@ static int setConfigSaveOption(typeData data, sds *argv, int argc, const char **
return
1
;
}
static
sds
getConfigSaveOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigSaveOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
sds
buf
=
sdsempty
();
int
j
;
...
...
@@ -2489,13 +2600,13 @@ static sds getConfigSaveOption(typeData data) {
return
buf
;
}
static
int
setConfigClientOutputBufferLimitOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigClientOutputBufferLimitOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
return
updateClientOutputBufferLimit
(
argv
,
argc
,
err
);
}
static
sds
getConfigClientOutputBufferLimitOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigClientOutputBufferLimitOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
sds
buf
=
sdsempty
();
int
j
;
for
(
j
=
0
;
j
<
CLIENT_TYPE_OBUF_COUNT
;
j
++
)
{
...
...
@@ -2513,11 +2624,11 @@ static sds getConfigClientOutputBufferLimitOption(typeData data) {
/* Parse an array of CONFIG_OOM_COUNT sds strings, validate and populate
* server.oom_score_adj_values if valid.
*/
static
int
setConfigOOMScoreAdjValuesOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
static
int
setConfigOOMScoreAdjValuesOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
int
i
;
int
values
[
CONFIG_OOM_COUNT
];
int
change
=
0
;
UNUSED
(
data
);
UNUSED
(
config
);
if
(
argc
!=
CONFIG_OOM_COUNT
)
{
*
err
=
"wrong number of arguments"
;
...
...
@@ -2558,8 +2669,8 @@ static int setConfigOOMScoreAdjValuesOption(typeData data, sds *argv, int argc,
return
change
?
1
:
2
;
}
static
sds
getConfigOOMScoreAdjValuesOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigOOMScoreAdjValuesOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
sds
buf
=
sdsempty
();
int
j
;
...
...
@@ -2572,8 +2683,8 @@ static sds getConfigOOMScoreAdjValuesOption(typeData data) {
return
buf
;
}
static
int
setConfigNotifyKeyspaceEventsOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigNotifyKeyspaceEventsOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
if
(
argc
!=
1
)
{
*
err
=
"wrong number of arguments"
;
return
0
;
...
...
@@ -2587,13 +2698,13 @@ static int setConfigNotifyKeyspaceEventsOption(typeData data, sds *argv, int arg
return
1
;
}
static
sds
getConfigNotifyKeyspaceEventsOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigNotifyKeyspaceEventsOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
return
keyspaceEventsFlagsToString
(
server
.
notify_keyspace_events
);
}
static
int
setConfigBindOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigBindOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
int
j
;
if
(
argc
>
CONFIG_BINDADDR_MAX
)
{
...
...
@@ -2615,8 +2726,8 @@ static int setConfigBindOption(typeData data, sds* argv, int argc, const char **
return
1
;
}
static
int
setConfigReplicaOfOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigReplicaOfOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
if
(
argc
!=
2
)
{
*
err
=
"wrong number of arguments"
;
...
...
@@ -2639,13 +2750,13 @@ static int setConfigReplicaOfOption(typeData data, sds* argv, int argc, const ch
return
1
;
}
static
sds
getConfigBindOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigBindOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
return
sdsjoin
(
server
.
bindaddr
,
server
.
bindaddr_count
,
" "
);
}
static
sds
getConfigReplicaOfOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigReplicaOfOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
char
buf
[
256
];
if
(
server
.
masterhost
)
snprintf
(
buf
,
sizeof
(
buf
),
"%s %d"
,
...
...
@@ -2661,8 +2772,8 @@ int allowProtectedAction(int config, client *c) {
}
static
int
setConfigLatencyTrackingInfoPercentilesOutputOption
(
typeData
data
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
data
);
static
int
setConfigLatencyTrackingInfoPercentilesOutputOption
(
standardConfig
*
config
,
sds
*
argv
,
int
argc
,
const
char
**
err
)
{
UNUSED
(
config
);
zfree
(
server
.
latency_tracking_info_percentiles
);
server
.
latency_tracking_info_percentiles
=
NULL
;
server
.
latency_tracking_info_percentiles_len
=
argc
;
...
...
@@ -2694,8 +2805,8 @@ configerr:
return
0
;
}
static
sds
getConfigLatencyTrackingInfoPercentilesOutputOption
(
typeData
data
)
{
UNUSED
(
data
);
static
sds
getConfigLatencyTrackingInfoPercentilesOutputOption
(
standardConfig
*
config
)
{
UNUSED
(
config
);
sds
buf
=
sdsempty
();
for
(
int
j
=
0
;
j
<
server
.
latency_tracking_info_percentiles_len
;
j
++
)
{
char
fbuf
[
128
];
...
...
@@ -2709,8 +2820,8 @@ static sds getConfigLatencyTrackingInfoPercentilesOutputOption(typeData data) {
}
/* Rewrite the latency-tracking-info-percentiles option. */
void
rewriteConfigLatencyTrackingInfoPercentilesOutputOption
(
typeData
data
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
data
);
void
rewriteConfigLatencyTrackingInfoPercentilesOutputOption
(
standardConfig
*
config
,
const
char
*
name
,
struct
rewriteConfigState
*
state
)
{
UNUSED
(
config
);
sds
line
=
sdsnew
(
name
);
/* Rewrite latency-tracking-info-percentiles parameters,
* or an empty 'latency-tracking-info-percentiles ""' line to avoid the
...
...
@@ -2729,7 +2840,7 @@ void rewriteConfigLatencyTrackingInfoPercentilesOutputOption(typeData data, cons
rewriteConfigRewriteLine
(
state
,
name
,
line
,
1
);
}
standardConfig
configs
[]
=
{
standardConfig
static_
configs
[]
=
{
/* Bool configs */
createBoolConfig
(
"rdbchecksum"
,
NULL
,
IMMUTABLE_CONFIG
,
server
.
rdb_checksum
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"daemonize"
,
NULL
,
IMMUTABLE_CONFIG
,
server
.
daemonize
,
0
,
NULL
,
NULL
),
...
...
@@ -2771,7 +2882,7 @@ standardConfig configs[] = {
createBoolConfig
(
"crash-log-enabled"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
crashlog_enabled
,
1
,
NULL
,
updateSighandlerEnabled
),
createBoolConfig
(
"crash-memcheck-enabled"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
memcheck_enabled
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"use-exit-on-panic"
,
NULL
,
MODIFIABLE_CONFIG
|
HIDDEN_CONFIG
,
server
.
use_exit_on_panic
,
0
,
NULL
,
NULL
),
createBoolConfig
(
"disable-thp"
,
NULL
,
MODIFI
ABLE_CONFIG
,
server
.
disable_thp
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"disable-thp"
,
NULL
,
IMMUT
ABLE_CONFIG
,
server
.
disable_thp
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"cluster-allow-replica-migration"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
cluster_allow_replica_migration
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"replica-announced"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
replica_announced
,
1
,
NULL
,
NULL
),
createBoolConfig
(
"latency-tracking"
,
NULL
,
MODIFIABLE_CONFIG
,
server
.
latency_tracking_enabled
,
1
,
NULL
,
NULL
),
...
...
@@ -2930,10 +3041,105 @@ standardConfig configs[] = {
createSpecialConfig
(
"replicaof"
,
"slaveof"
,
IMMUTABLE_CONFIG
|
MULTI_ARG_CONFIG
,
setConfigReplicaOfOption
,
getConfigReplicaOfOption
,
rewriteConfigReplicaOfOption
,
NULL
),
createSpecialConfig
(
"latency-tracking-info-percentiles"
,
NULL
,
MODIFIABLE_CONFIG
|
MULTI_ARG_CONFIG
,
setConfigLatencyTrackingInfoPercentilesOutputOption
,
getConfigLatencyTrackingInfoPercentilesOutputOption
,
rewriteConfigLatencyTrackingInfoPercentilesOutputOption
,
NULL
),
/* NULL Terminator */
/* NULL Terminator
, this is dropped when we convert to the runtime array.
*/
{
NULL
}
};
/* Create a new config by copying the passed in config. Returns 1 on success
* or 0 when their was already a config with the same name.. */
int
registerConfigValue
(
const
char
*
name
,
const
standardConfig
*
config
,
int
alias
)
{
standardConfig
*
new
=
zmalloc
(
sizeof
(
standardConfig
));
memcpy
(
new
,
config
,
sizeof
(
standardConfig
));
if
(
alias
)
{
new
->
flags
|=
ALIAS_CONFIG
;
new
->
name
=
config
->
alias
;
new
->
alias
=
config
->
name
;
}
return
dictAdd
(
configs
,
sdsnew
(
name
),
new
)
==
DICT_OK
;
}
/* Initialize configs to their default values and create and populate the
* runtime configuration dictionary. */
void
initConfigValues
()
{
configs
=
dictCreate
(
&
sdsHashDictType
);
dictExpand
(
configs
,
sizeof
(
static_configs
)
/
sizeof
(
standardConfig
));
for
(
standardConfig
*
config
=
static_configs
;
config
->
name
!=
NULL
;
config
++
)
{
if
(
config
->
interface
.
init
)
config
->
interface
.
init
(
config
);
/* Add the primary config to the dictionary. */
int
ret
=
registerConfigValue
(
config
->
name
,
config
,
0
);
serverAssert
(
ret
);
/* Aliases are the same as their primary counter parts, but they
* also have a flag indicating they are the alias. */
if
(
config
->
alias
)
{
int
ret
=
registerConfigValue
(
config
->
alias
,
config
,
ALIAS_CONFIG
);
serverAssert
(
ret
);
}
}
}
/* Remove a config by name from the configs dict. */
void
removeConfig
(
sds
name
)
{
standardConfig
*
config
=
lookupConfig
(
name
);
if
(
!
config
)
return
;
if
(
config
->
flags
&
MODULE_CONFIG
)
{
sdsfree
((
sds
)
config
->
name
);
if
(
config
->
type
==
ENUM_CONFIG
)
{
configEnum
*
enumNode
=
config
->
data
.
enumd
.
enum_value
;
while
(
enumNode
->
name
!=
NULL
)
{
zfree
(
enumNode
->
name
);
enumNode
++
;
}
zfree
(
config
->
data
.
enumd
.
enum_value
);
}
else
if
(
config
->
type
==
SDS_CONFIG
)
{
if
(
config
->
data
.
sds
.
default_value
)
sdsfree
((
sds
)
config
->
data
.
sds
.
default_value
);
}
}
dictDelete
(
configs
,
name
);
}
/*-----------------------------------------------------------------------------
* Module Config
*----------------------------------------------------------------------------*/
/* Create a bool/string/enum/numeric standardConfig for a module config in the configs dictionary */
void
addModuleBoolConfig
(
const
char
*
module_name
,
const
char
*
name
,
int
flags
,
void
*
privdata
,
int
default_val
)
{
sds
config_name
=
sdscatfmt
(
sdsempty
(),
"%s.%s"
,
module_name
,
name
);
int
config_dummy_address
;
standardConfig
module_config
=
createBoolConfig
(
config_name
,
NULL
,
flags
|
MODULE_CONFIG
,
config_dummy_address
,
default_val
,
NULL
,
NULL
);
module_config
.
data
.
yesno
.
config
=
NULL
;
module_config
.
privdata
=
privdata
;
registerConfigValue
(
config_name
,
&
module_config
,
0
);
}
void
addModuleStringConfig
(
const
char
*
module_name
,
const
char
*
name
,
int
flags
,
void
*
privdata
,
sds
default_val
)
{
sds
config_name
=
sdscatfmt
(
sdsempty
(),
"%s.%s"
,
module_name
,
name
);
sds
config_dummy_address
;
standardConfig
module_config
=
createSDSConfig
(
config_name
,
NULL
,
flags
|
MODULE_CONFIG
,
0
,
config_dummy_address
,
default_val
,
NULL
,
NULL
);
module_config
.
data
.
sds
.
config
=
NULL
;
module_config
.
privdata
=
privdata
;
registerConfigValue
(
config_name
,
&
module_config
,
0
);
}
void
addModuleEnumConfig
(
const
char
*
module_name
,
const
char
*
name
,
int
flags
,
void
*
privdata
,
int
default_val
,
configEnum
*
enum_vals
)
{
sds
config_name
=
sdscatfmt
(
sdsempty
(),
"%s.%s"
,
module_name
,
name
);
int
config_dummy_address
;
standardConfig
module_config
=
createEnumConfig
(
config_name
,
NULL
,
flags
|
MODULE_CONFIG
,
enum_vals
,
config_dummy_address
,
default_val
,
NULL
,
NULL
);
module_config
.
data
.
enumd
.
config
=
NULL
;
module_config
.
privdata
=
privdata
;
registerConfigValue
(
config_name
,
&
module_config
,
0
);
}
void
addModuleNumericConfig
(
const
char
*
module_name
,
const
char
*
name
,
int
flags
,
void
*
privdata
,
long
long
default_val
,
int
conf_flags
,
long
long
lower
,
long
long
upper
)
{
sds
config_name
=
sdscatfmt
(
sdsempty
(),
"%s.%s"
,
module_name
,
name
);
long
long
config_dummy_address
;
standardConfig
module_config
=
createLongLongConfig
(
config_name
,
NULL
,
flags
|
MODULE_CONFIG
,
lower
,
upper
,
config_dummy_address
,
default_val
,
conf_flags
,
NULL
,
NULL
);
module_config
.
data
.
numeric
.
config
.
ll
=
NULL
;
module_config
.
privdata
=
privdata
;
registerConfigValue
(
config_name
,
&
module_config
,
0
);
}
/*-----------------------------------------------------------------------------
* CONFIG HELP
*----------------------------------------------------------------------------*/
...
...
@@ -2975,8 +3181,10 @@ void configRewriteCommand(client *c) {
return
;
}
if
(
rewriteConfig
(
server
.
configfile
,
0
)
==
-
1
)
{
serverLog
(
LL_WARNING
,
"CONFIG REWRITE failed: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"Rewriting config file: %s"
,
strerror
(
errno
));
/* save errno in case of being tainted. */
int
err
=
errno
;
serverLog
(
LL_WARNING
,
"CONFIG REWRITE failed: %s"
,
strerror
(
err
));
addReplyErrorFormat
(
c
,
"Rewriting config file: %s"
,
strerror
(
err
));
}
else
{
serverLog
(
LL_WARNING
,
"CONFIG REWRITE executed with success."
);
addReply
(
c
,
shared
.
ok
);
...
...
Prev
1
2
3
4
5
6
7
8
9
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment