1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-04-13 11:30:40 +02:00

Store config values as a union instead of a variant.

The variants were needed to easily serialize configurations for the Perl code.

Unions are more efficient and will allow us to add new types that are not supported by variants, e.g. StringId.
This commit is contained in:
David Steele 2021-10-22 18:02:20 -04:00 committed by GitHub
parent 2cea005f74
commit 51785739f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 352 additions and 302 deletions

View File

@ -156,6 +156,17 @@
<p><proper>Add TLS</proper> server.</p>
</release-item>
<release-item>
<github-pull-request id="1543"/>
<release-item-contributor-list>
<release-item-contributor id="david.steele"/>
<release-item-reviewer id="reid.thompson"/>
</release-item-contributor-list>
<p>Store config values as a union instead of a variant.</p>
</release-item>
</release-development-list>
</release-core-list>

View File

@ -386,7 +386,8 @@ backupBuildIncrPrior(const InfoBackup *infoBackup)
CHECK(manifestPriorData->backupOptionCompressLevel != NULL);
// Set the compression level back to whatever was in the prior backup
cfgOptionSet(cfgOptCompressLevel, cfgSourceParam, manifestPriorData->backupOptionCompressLevel);
cfgOptionSet(
cfgOptCompressLevel, cfgSourceParam, VARINT64(varUInt(manifestPriorData->backupOptionCompressLevel)));
}
// Warn if hardlink option changed ??? Doesn't seem like this is needed? Hardlinks are always to a directory that

View File

@ -337,7 +337,7 @@ expireTimeBasedBackup(InfoBackup *infoBackup, const time_t minTimestamp, unsigne
{
cfgOptionIdxSet(
cfgOptRepoRetentionArchive, repoIdx, cfgSourceDefault,
varNewUInt(strLstSize(currentBackupList) - numFullExpired));
VARINT64(strLstSize(currentBackupList) - numFullExpired));
}
}
}

View File

@ -453,7 +453,7 @@ helpRender(const Buffer *const helpData)
const String *value = NULL;
if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
value = helpRenderValue(cfgOptionIdx(optionId, 0), cfgParseOptionType(optionId));
value = helpRenderValue(cfgOptionIdxVar(optionId, 0), cfgParseOptionType(optionId));
if (value != NULL || defaultValue != NULL)
{
@ -520,7 +520,7 @@ helpRender(const Buffer *const helpData)
const String *value = NULL;
if (cfgOptionIdxSource(option.id, 0) != cfgSourceDefault)
value = helpRenderValue(cfgOptionIdx(option.id, 0), cfgParseOptionType(option.id));
value = helpRenderValue(cfgOptionIdxVar(option.id, 0), cfgParseOptionType(option.id));
if (value != NULL || defaultValue != NULL)
{

View File

@ -440,7 +440,7 @@ restoreManifestMap(Manifest *manifest)
// Remap tablespaces
// -------------------------------------------------------------------------------------------------------------------------
KeyValue *tablespaceMap = varKv(cfgOption(cfgOptTablespaceMap));
const KeyValue *const tablespaceMap = cfgOptionKvNull(cfgOptTablespaceMap);
const String *tablespaceMapAllPath = cfgOptionStrNull(cfgOptTablespaceMapAll);
if (tablespaceMap != NULL || tablespaceMapAllPath != NULL)
@ -527,7 +527,7 @@ restoreManifestMap(Manifest *manifest)
// Remap links
// -------------------------------------------------------------------------------------------------------------------------
const KeyValue *const linkMap = varKv(cfgOption(cfgOptLinkMap));
const KeyValue *const linkMap = cfgOptionKvNull(cfgOptLinkMap);
if (linkMap != NULL)
{

View File

@ -3,6 +3,7 @@ Command and Option Configuration
***********************************************************************************************************************************/
#include "build.auto.h"
#include <limits.h>
#include <string.h>
#include "common/debug.h"
@ -404,6 +405,7 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
ASSERT(optionId < CFG_OPTION_TOTAL);
ASSERT(configLocal != NULL);
ASSERT(configLocal->option[optionId].valid);
ASSERT(cfgParseOptionDataType(optionId) == cfgOptDataTypeString);
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
@ -418,7 +420,8 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
{
if (configLocal->option[optionId].index[optionIdx].source == cfgSourceDefault)
{
configLocal->option[optionId].index[optionIdx].value = defaultValue;
configLocal->option[optionId].index[optionIdx].set = true;
configLocal->option[optionId].index[optionIdx].value.string = varStr(defaultValue);
configLocal->option[optionId].index[optionIdx].display = NULL;
}
}
@ -485,7 +488,7 @@ cfgOptionIdxDisplay(const ConfigOption optionId, const unsigned int optionIdx)
// Generate the display value based on the type
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
option->display = cfgOptionDisplayVar(option->value, cfgParseOptionType(optionId));
option->display = cfgOptionDisplayVar(cfgOptionIdxVar(optionId, optionIdx), cfgParseOptionType(optionId));
}
MEM_CONTEXT_END();
@ -699,8 +702,9 @@ cfgOptionIdxReset(ConfigOption optionId, unsigned int optionIdx)
/**********************************************************************************************************************************/
// Helper to enforce contraints when getting options
static const Variant *
cfgOptionIdxInternal(ConfigOption optionId, unsigned int optionIdx, VariantType typeRequested, bool nullAllowed)
static const ConfigOptionValue *
cfgOptionIdxInternal(
const ConfigOption optionId, const unsigned int optionIdx, const ConfigOptionDataType typeRequested, const bool nullAllowed)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
@ -721,15 +725,15 @@ cfgOptionIdxInternal(ConfigOption optionId, unsigned int optionIdx, VariantType
THROW_FMT(AssertError, "option '%s' is not valid for the current command", cfgOptionIdxName(optionId, optionIdx));
// If the option is not NULL then check it is the requested type
const Variant *result = configLocal->option[optionId].index[optionIdx].value;
const ConfigOptionValue *const result = &configLocal->option[optionId].index[optionIdx];
if (result != NULL)
if (result->set)
{
if (varType(result) != typeRequested)
if (configLocal->option[optionId].dataType != typeRequested)
{
THROW_FMT(
AssertError, "option '%s' is type %u but %u was requested", cfgOptionIdxName(optionId, optionIdx), varType(result),
typeRequested);
AssertError, "option '%s' is type %u but %u was requested", cfgOptionIdxName(optionId, optionIdx),
configLocal->option[optionId].dataType, typeRequested);
}
}
// Else check the option is allowed to be NULL
@ -739,18 +743,8 @@ cfgOptionIdxInternal(ConfigOption optionId, unsigned int optionIdx, VariantType
FUNCTION_TEST_RETURN(result);
}
const Variant *
cfgOption(ConfigOption optionId)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
FUNCTION_TEST_END();
FUNCTION_TEST_RETURN(cfgOptionIdx(optionId, cfgOptionIdxDefault(optionId)));
}
const Variant *
cfgOptionIdx(ConfigOption optionId, unsigned int optionIdx)
Variant *
cfgOptionIdxVar(const ConfigOption optionId, const unsigned int optionIdx)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
@ -763,122 +757,94 @@ cfgOptionIdx(ConfigOption optionId, unsigned int optionIdx)
(configLocal->option[optionId].group && optionIdx <
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
FUNCTION_TEST_RETURN(configLocal->option[optionId].index[optionIdx].value);
if (configLocal->option[optionId].index[optionIdx].set)
{
switch (configLocal->option[optionId].dataType)
{
case cfgOptDataTypeBoolean:
FUNCTION_TEST_RETURN(varNewBool(configLocal->option[optionId].index[optionIdx].value.boolean));
case cfgOptDataTypeHash:
FUNCTION_TEST_RETURN(varNewKv(kvDup(configLocal->option[optionId].index[optionIdx].value.keyValue)));
case cfgOptDataTypeInteger:
FUNCTION_TEST_RETURN(varNewInt64(configLocal->option[optionId].index[optionIdx].value.integer));
case cfgOptDataTypeList:
FUNCTION_TEST_RETURN(varNewVarLst(configLocal->option[optionId].index[optionIdx].value.list));
default:
ASSERT(configLocal->option[optionId].dataType == cfgOptDataTypeString);
break;
}
FUNCTION_TEST_RETURN(varNewStr(configLocal->option[optionId].index[optionIdx].value.string));
}
FUNCTION_TEST_RETURN(NULL);
}
bool
cfgOptionBool(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(BOOL, varBool(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeBool, false)));
}
bool
cfgOptionIdxBool(ConfigOption optionId, unsigned int optionIdx)
cfgOptionIdxBool(const ConfigOption optionId, unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(BOOL, varBool(cfgOptionIdxInternal(optionId, optionIdx, varTypeBool, false)));
FUNCTION_LOG_RETURN(BOOL, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeBoolean, false)->value.boolean);
}
int
cfgOptionInt(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(INT, varIntForce(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
}
int
cfgOptionIdxInt(ConfigOption optionId, unsigned int optionIdx)
cfgOptionIdxInt(const ConfigOption optionId, const unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(INT, varIntForce(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
ASSERT(cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer >= INT_MIN);
ASSERT(cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer <= INT_MAX);
FUNCTION_LOG_RETURN(INT, (int)cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer);
}
int64_t
cfgOptionInt64(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(INT64, varInt64(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
}
int64_t
cfgOptionIdxInt64(ConfigOption optionId, unsigned int optionIdx)
cfgOptionIdxInt64(const ConfigOption optionId, const unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(INT64, varInt64(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
FUNCTION_LOG_RETURN(INT64, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer);
}
unsigned int
cfgOptionUInt(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(UINT, varUIntForce(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
}
unsigned int
cfgOptionIdxUInt(ConfigOption optionId, unsigned int optionIdx)
cfgOptionIdxUInt(const ConfigOption optionId, const unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(UINT, varUIntForce(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
ASSERT(cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer >= 0);
ASSERT(cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer <= UINT_MAX);
FUNCTION_LOG_RETURN(UINT, (unsigned int)cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer);
}
uint64_t
cfgOptionUInt64(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(UINT64, varUInt64Force(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeInt64, false)));
}
uint64_t
cfgOptionIdxUInt64(ConfigOption optionId, unsigned int optionIdx)
cfgOptionIdxUInt64(const ConfigOption optionId, const unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(UINT64, varUInt64Force(cfgOptionIdxInternal(optionId, optionIdx, varTypeInt64, false)));
}
ASSERT(cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer >= 0);
const KeyValue *
cfgOptionKv(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(KEY_VALUE, varKv(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeKeyValue, false)));
FUNCTION_LOG_RETURN(UINT64, (uint64_t)cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeInteger, false)->value.integer);
}
const KeyValue *
@ -889,17 +855,18 @@ cfgOptionIdxKv(ConfigOption optionId, unsigned int optionIdx)
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(KEY_VALUE, varKv(cfgOptionIdxInternal(optionId, optionIdx, varTypeKeyValue, false)));
FUNCTION_LOG_RETURN_CONST(KEY_VALUE, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeHash, false)->value.keyValue);
}
const VariantList *
cfgOptionLst(ConfigOption optionId)
const KeyValue *
cfgOptionIdxKvNull(ConfigOption optionId, unsigned int optionIdx)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN_CONST(VARIANT_LIST, cfgOptionIdxLst(optionId, cfgOptionIdxDefault(optionId)));
FUNCTION_LOG_RETURN_CONST(KEY_VALUE, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeHash, true)->value.keyValue);
}
const VariantList *
@ -912,29 +879,19 @@ cfgOptionIdxLst(ConfigOption optionId, unsigned int optionIdx)
ASSERT(configLocal != NULL);
const Variant *optionValue = cfgOptionIdxInternal(optionId, optionIdx, varTypeVariantList, true);
const VariantList *optionValue = cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeList, true)->value.list;
if (optionValue == NULL)
{
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
optionValue = varNewVarLst(varLstNew());
configLocal->option[optionId].index[optionIdx].value = optionValue;
optionValue = varLstNew();
configLocal->option[optionId].index[optionIdx].value.list = optionValue;
}
MEM_CONTEXT_END();
}
FUNCTION_LOG_RETURN(VARIANT_LIST, varVarLst(optionValue));
}
const String *
cfgOptionStr(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeString, false)));
FUNCTION_LOG_RETURN_CONST(VARIANT_LIST, optionValue);
}
const String *
@ -945,17 +902,7 @@ cfgOptionIdxStr(ConfigOption optionId, unsigned int optionIdx)
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, false)));
}
const String *
cfgOptionStrNull(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, cfgOptionIdxDefault(optionId), varTypeString, true)));
FUNCTION_LOG_RETURN_CONST(STRING, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeString, false)->value.string);
}
const String *
@ -966,7 +913,7 @@ cfgOptionIdxStrNull(ConfigOption optionId, unsigned int optionIdx)
FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN_CONST(STRING, varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, true)));
FUNCTION_LOG_RETURN_CONST(STRING, cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeString, true)->value.string);
}
// Helper to convert option String values to StringIds. Some options need 6-bit encoding while most work fine with 5-bit encoding.
@ -981,7 +928,7 @@ cfgOptionStrIdInternal(
FUNCTION_TEST_PARAM(UINT, optionIdx);
FUNCTION_TEST_END();
const String *const value = varStr(cfgOptionIdxInternal(optionId, optionIdx, varTypeString, false));
const String *const value = cfgOptionIdxInternal(optionId, optionIdx, cfgOptDataTypeString, false)->value.string;
StringId result = 0;
TRY_BEGIN()
@ -997,16 +944,6 @@ cfgOptionStrIdInternal(
FUNCTION_TEST_RETURN(result);
}
StringId
cfgOptionStrId(ConfigOption optionId)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_END();
FUNCTION_LOG_RETURN(STRING_ID, cfgOptionStrIdInternal(optionId, cfgOptionIdxDefault(optionId)));
}
StringId
cfgOptionIdxStrId(ConfigOption optionId, unsigned int optionIdx)
{
@ -1050,63 +987,57 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
(configLocal->option[optionId].group && optionIdx <
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
MEM_CONTEXT_BEGIN(configLocal->memContext)
// Set the source
configLocal->option[optionId].index[optionIdx].source = source;
// Only set value if it is not null
if (value != NULL)
{
// Set the source
configLocal->option[optionId].index[optionIdx].source = source;
// Only set value if it is not null
if (value != NULL)
switch (configLocal->option[optionId].dataType)
{
switch (cfgParseOptionType(optionId))
case cfgOptDataTypeBoolean:
configLocal->option[optionId].index[optionIdx].value.boolean = varBool(value);
break;
case cfgOptDataTypeInteger:
configLocal->option[optionId].index[optionIdx].value.integer = varInt64(value);
break;
case cfgOptDataTypeString:
{
case cfgOptTypeBoolean:
if (varType(value) == varTypeString)
{
if (varType(value) == varTypeBool)
configLocal->option[optionId].index[optionIdx].value = varDup(value);
else
configLocal->option[optionId].index[optionIdx].value = varNewBool(varBoolForce(value));
break;
}
case cfgOptTypeInteger:
case cfgOptTypeSize:
case cfgOptTypeTime:
{
if (varType(value) == varTypeInt64)
configLocal->option[optionId].index[optionIdx].value = varDup(value);
else
configLocal->option[optionId].index[optionIdx].value = varNewInt64(varInt64Force(value));
break;
}
case cfgOptTypePath:
case cfgOptTypeString:
{
if (varType(value) == varTypeString)
configLocal->option[optionId].index[optionIdx].value = varDup(value);
else
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
THROW_FMT(
AssertError, "option '%s' must be set with String variant", cfgOptionIdxName(optionId, optionIdx));
configLocal->option[optionId].index[optionIdx].value.string = strDup(varStr(value));
}
break;
MEM_CONTEXT_END();
}
else
{
THROW_FMT(
AssertError, "option '%s' must be set with String variant", cfgOptionIdxName(optionId, optionIdx));
}
default:
THROW_FMT(AssertError, "set not available for option type %u", cfgParseOptionType(optionId));
break;
}
}
else
configLocal->option[optionId].index[optionIdx].value = NULL;
// Clear the display value, which will be generated when needed
configLocal->option[optionId].index[optionIdx].display = NULL;
default:
THROW_FMT(AssertError, "set not available for option data type %u", configLocal->option[optionId].dataType);
}
configLocal->option[optionId].index[optionIdx].set = true;
}
MEM_CONTEXT_END();
else
{
configLocal->option[optionId].index[optionIdx].set = false;
// Pointer values need to be set to null since they can be accessed when the option is not set, e.g. cfgOptionStrNull().
configLocal->option[optionId].index[optionIdx].value.string = NULL;
}
// Clear the display value, which will be generated when needed
configLocal->option[optionId].index[optionIdx].display = NULL;
FUNCTION_TEST_RETURN_VOID();
}
@ -1167,7 +1098,7 @@ cfgOptionIdxTest(ConfigOption optionId, unsigned int optionIdx)
(configLocal->option[optionId].group && optionIdx <
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal)));
FUNCTION_TEST_RETURN(cfgOptionValid(optionId) && configLocal->option[optionId].index[optionIdx].value != NULL);
FUNCTION_TEST_RETURN(cfgOptionValid(optionId) && configLocal->option[optionId].index[optionIdx].set);
}
/**********************************************************************************************************************************/

View File

@ -101,30 +101,106 @@ Option Functions
Access option values, indexes, and determine if an option is valid for the current command. Most functions have a variant that
accepts an index, which currently work with non-indexed options (with optionIdx 0) but they may not always do so.
***********************************************************************************************************************************/
// Get config options for various types
const Variant *cfgOption(ConfigOption optionId);
const Variant *cfgOptionIdx(ConfigOption optionId, unsigned int optionIdx);
bool cfgOptionBool(ConfigOption optionId);
// Get default index for a group option
unsigned int cfgOptionIdxDefault(ConfigOption optionId);
// Get boolean config option
bool cfgOptionIdxBool(ConfigOption optionId, unsigned int optionIdx);
int cfgOptionInt(ConfigOption optionId);
__attribute__((always_inline)) static inline bool
cfgOptionBool(const ConfigOption optionId)
{
return cfgOptionIdxBool(optionId, cfgOptionIdxDefault(optionId));
}
// Get int config option
int cfgOptionIdxInt(ConfigOption optionId, unsigned int optionIdx);
int64_t cfgOptionInt64(ConfigOption optionId);
__attribute__((always_inline)) static inline int
cfgOptionInt(const ConfigOption optionId)
{
return cfgOptionIdxInt(optionId, cfgOptionIdxDefault(optionId));
}
// Get int64 config option
int64_t cfgOptionIdxInt64(ConfigOption optionId, unsigned int optionIdx);
const KeyValue *cfgOptionKv(ConfigOption optionId);
__attribute__((always_inline)) static inline int64_t
cfgOptionInt64(const ConfigOption optionId)
{
return cfgOptionIdxInt64(optionId, cfgOptionIdxDefault(optionId));
}
// Get kv config option
const KeyValue *cfgOptionIdxKv(ConfigOption optionId, unsigned int optionIdx);
const VariantList *cfgOptionLst(ConfigOption optionId);
__attribute__((always_inline)) static inline const KeyValue *
cfgOptionKv(const ConfigOption optionId)
{
return cfgOptionIdxKv(optionId, cfgOptionIdxDefault(optionId));
}
const KeyValue *cfgOptionIdxKvNull(ConfigOption optionId, unsigned int optionIdx);
__attribute__((always_inline)) static inline const KeyValue *
cfgOptionKvNull(const ConfigOption optionId)
{
return cfgOptionIdxKvNull(optionId, cfgOptionIdxDefault(optionId));
}
// Get list config option
const VariantList *cfgOptionIdxLst(ConfigOption optionId, unsigned int optionIdx);
const String *cfgOptionStr(ConfigOption optionId);
__attribute__((always_inline)) static inline const VariantList *
cfgOptionLst(const ConfigOption optionId)
{
return cfgOptionIdxLst(optionId, cfgOptionIdxDefault(optionId));
}
// Get String config option
const String *cfgOptionIdxStr(ConfigOption optionId, unsigned int optionIdx);
StringId cfgOptionStrId(ConfigOption optionId);
StringId cfgOptionIdxStrId(ConfigOption optionId, unsigned int optionIdx);
const String *cfgOptionStrNull(ConfigOption optionId);
__attribute__((always_inline)) static inline const String *
cfgOptionStr(const ConfigOption optionId)
{
return cfgOptionIdxStr(optionId, cfgOptionIdxDefault(optionId));
}
const String *cfgOptionIdxStrNull(ConfigOption optionId, unsigned int optionIdx);
unsigned int cfgOptionUInt(ConfigOption optionId);
__attribute__((always_inline)) static inline const String *
cfgOptionStrNull(const ConfigOption optionId)
{
return cfgOptionIdxStrNull(optionId, cfgOptionIdxDefault(optionId));
}
// Get StringId config option
StringId cfgOptionIdxStrId(ConfigOption optionId, unsigned int optionIdx);
__attribute__((always_inline)) static inline StringId
cfgOptionStrId(const ConfigOption optionId)
{
return cfgOptionIdxStrId(optionId, cfgOptionIdxDefault(optionId));
}
// Get uint config option
unsigned int cfgOptionIdxUInt(ConfigOption optionId, unsigned int optionIdx);
uint64_t cfgOptionUInt64(ConfigOption optionId);
__attribute__((always_inline)) static inline unsigned int
cfgOptionUInt(const ConfigOption optionId)
{
return cfgOptionIdxUInt(optionId, cfgOptionIdxDefault(optionId));
}
// Get uint64 config option
uint64_t cfgOptionIdxUInt64(ConfigOption optionId, unsigned int optionIdx);
__attribute__((always_inline)) static inline uint64_t
cfgOptionUInt64(const ConfigOption optionId)
{
return cfgOptionIdxUInt64(optionId, cfgOptionIdxDefault(optionId));
}
// Format the configuration value for display to the user or passing on a command line. If the value was set by the user via the
// command line, config, etc., then that exact value will be displayed. This makes it easier for the user to recognize the value and
// saves having to format it into something reasonable, especially for time and size option types. Note that cfgOptTypeHash and

View File

@ -21,13 +21,23 @@ The maximum number of keys that an indexed option can have, e.g. pg256-path woul
Configuration data. These structures are not directly user-created or accessible. configParse() creates the structures and uses
cfgInit() to load it as the current configuration. Various cfg*() functions provide access.
***********************************************************************************************************************************/
typedef union ConfigOptionValueType
{
bool boolean; // Boolean
int64_t integer; // Integer
const KeyValue *keyValue; // KeyValue
const VariantList *list; // VariantList
const String *string; // String
} ConfigOptionValueType;
typedef struct ConfigOptionValue
{
bool set; // Is the option set?
bool negate; // Is the option negated?
bool reset; // Is the option reset?
unsigned int source; // Where the option came from, i.e. ConfigSource enum
const String *display; // Current display value, if any. Used for messages, etc.
const Variant *value; // Value
ConfigOptionValueType value; // Option value
} ConfigOptionValue;
typedef struct Config
@ -65,6 +75,7 @@ typedef struct Config
bool valid; // Is option valid for current command?
bool group; // In a group?
unsigned int groupId; // Id if in a group
ConfigOptionDataType dataType; // Underlying data type
const String *defaultValue; // Default value
ConfigOptionValue *index; // List of indexed values (only 1 unless the option is indexed)
} option[CFG_OPTION_TOTAL];
@ -108,6 +119,15 @@ unsigned int cfgOptionKeyToIdx(ConfigOption optionId, unsigned int key);
// Total indexes for the option if in a group, 1 otherwise.
unsigned int cfgOptionIdxTotal(ConfigOption optionId);
// Get config option as a Variant
Variant *cfgOptionIdxVar(ConfigOption optionId, unsigned int optionIdx);
__attribute__((always_inline)) static inline Variant *
cfgOptionVar(const ConfigOption optionId)
{
return cfgOptionIdxVar(optionId, cfgOptionIdxDefault(optionId));
}
// Invalidate an option so it will not be passed to other processes. This is used to manage deprecated options that have a newer
// option that should be used when possible, e.g. compress and compress-type.
void cfgOptionInvalidate(ConfigOption optionId);

View File

@ -71,7 +71,7 @@ cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const Key
if (cfgOptionIdxNegate(optionId, optionIdx))
value = BOOL_FALSE_VAR;
else if (cfgOptionIdxSource(optionId, optionIdx) != cfgSourceDefault)
value = cfgOptionIdx(optionId, optionIdx);
value = cfgOptionIdxVar(optionId, optionIdx);
}
// If the option was reset

View File

@ -220,7 +220,7 @@ cfgLoadUpdateOption(void)
cfgOptionIdxTest(cfgOptRepoRetentionFull, optionIdx))
{
cfgOptionIdxSet(cfgOptRepoRetentionArchive, optionIdx, cfgSourceDefault,
VARUINT(cfgOptionIdxUInt(cfgOptRepoRetentionFull, optionIdx)));
VARINT64(cfgOptionIdxInt64(cfgOptRepoRetentionFull, optionIdx)));
}
break;
@ -232,7 +232,7 @@ cfgLoadUpdateOption(void)
if (cfgOptionIdxTest(cfgOptRepoRetentionDiff, optionIdx))
{
cfgOptionIdxSet(cfgOptRepoRetentionArchive, optionIdx, cfgSourceDefault,
VARUINT(cfgOptionIdxUInt(cfgOptRepoRetentionDiff, optionIdx)));
VARINT64(cfgOptionIdxInt64(cfgOptRepoRetentionDiff, optionIdx)));
}
else
{
@ -346,7 +346,7 @@ cfgLoadUpdateOption(void)
{
cfgOptionSet(
cfgOptCompressLevel, cfgSourceDefault,
VARINT(compressLevelDefault(compressTypeEnum(cfgOptionStr(cfgOptCompressType)))));
VARINT64(compressLevelDefault(compressTypeEnum(cfgOptionStr(cfgOptCompressType)))));
}
FUNCTION_LOG_RETURN_VOID();

View File

@ -661,18 +661,9 @@ cfgParseOption(const String *const optionCandidate, const CfgParseOptionParam pa
FUNCTION_TEST_RETURN((CfgParseOptionResult){0});
}
/***********************************************************************************************************************************
Get the underlying data type for an option
***********************************************************************************************************************************/
typedef enum
{
cfgOptDataTypeBoolean, // Boolean
cfgOptDataTypeInteger, // Signed 64-bit integer
cfgOptDataTypeString, // String
} ConfigOptionDataType;
static ConfigOptionDataType
cfgParseOptionDataType(ConfigOption optionId)
/**********************************************************************************************************************************/
ConfigOptionDataType
cfgParseOptionDataType(const ConfigOption optionId)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, optionId);
@ -685,13 +676,22 @@ cfgParseOptionDataType(ConfigOption optionId)
case cfgOptTypeBoolean:
FUNCTION_TEST_RETURN(cfgOptDataTypeBoolean);
case cfgOptTypeHash:
FUNCTION_TEST_RETURN(cfgOptDataTypeHash);
case cfgOptTypeInteger:
case cfgOptTypeSize:
case cfgOptTypeTime:
FUNCTION_TEST_RETURN(cfgOptDataTypeInteger);
case cfgOptTypeList:
FUNCTION_TEST_RETURN(cfgOptDataTypeList);
default:
break;
}
ASSERT(
parseRuleOption[optionId].type == cfgOptTypeHash || parseRuleOption[optionId].type == cfgOptTypeList ||
parseRuleOption[optionId].type == cfgOptTypePath || parseRuleOption[optionId].type == cfgOptTypeString);
ASSERT(parseRuleOption[optionId].type == cfgOptTypePath || parseRuleOption[optionId].type == cfgOptTypeString);
FUNCTION_TEST_RETURN(cfgOptDataTypeString);
}
@ -718,8 +718,8 @@ typedef struct CfgParseOptionalRuleState
size_t allowListSize;
// Default
const Variant *defaultValue;
const String *defaultRaw;
ConfigOptionValueType defaultValue;
// Required
bool required;
@ -737,12 +737,12 @@ cfgParseOptionalFilterDepend(PackRead *const filter, const Config *const config,
// Get the depend option value
const ConfigOption dependId = (ConfigOption)pckReadU32P(filter);
ASSERT(config->option[dependId].index != NULL);
const Variant *const dependValue = config->option[dependId].index[optionListIdx].value;
const ConfigOptionValue *const dependValue = &config->option[dependId].index[optionListIdx];
// Is the dependency resolved?
bool result = false;
if (dependValue != NULL)
if (dependValue->set)
{
// If a depend list exists, make sure the value is in the list
if (pckReadNext(filter))
@ -753,11 +753,11 @@ cfgParseOptionalFilterDepend(PackRead *const filter, const Config *const config,
{
TRY_BEGIN()
{
dependValueStrId = strIdFromStr(stringIdBit5, varStr(dependValue));
dependValueStrId = strIdFromStr(stringIdBit5, dependValue->value.string);
}
CATCH_ANY()
{
dependValueStrId = strIdFromStr(stringIdBit6, varStr(dependValue));
dependValueStrId = strIdFromStr(stringIdBit6, dependValue->value.string);
}
TRY_END();
}
@ -767,7 +767,7 @@ cfgParseOptionalFilterDepend(PackRead *const filter, const Config *const config,
switch (cfgParseOptionDataType(dependId))
{
case cfgOptDataTypeBoolean:
result = pckReadBoolP(filter) == varBool(dependValue);
result = pckReadBoolP(filter) == dependValue->value.boolean;
break;
default:
@ -948,8 +948,8 @@ cfgParseOptionalRule(
switch (pckReadType(ruleData))
{
case pckTypeBool:
optionalRules->defaultValue = pckReadBoolP(ruleData) ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
optionalRules->defaultRaw = varBool(optionalRules->defaultValue) ? Y_STR : N_STR;
optionalRules->defaultValue.boolean = pckReadBoolP(ruleData);
optionalRules->defaultRaw = optionalRules->defaultValue.boolean ? Y_STR : N_STR;
break;
default:
@ -960,7 +960,7 @@ cfgParseOptionalRule(
case cfgOptTypeTime:
case cfgOptTypeSize:
{
optionalRules->defaultValue = varNewInt64(parseRuleValueInt[pckReadU32P(ruleData)]);
optionalRules->defaultValue.integer = parseRuleValueInt[pckReadU32P(ruleData)];
optionalRules->defaultRaw = (const String *)&parseRuleValueStr[pckReadU32P(ruleData)];
break;
@ -970,7 +970,7 @@ cfgParseOptionalRule(
case cfgOptTypeString:
{
optionalRules->defaultRaw = (const String *)&parseRuleValueStr[pckReadU32P(ruleData)];
optionalRules->defaultValue = varNewStr(optionalRules->defaultRaw);
optionalRules->defaultValue.string = optionalRules->defaultRaw;
break;
}
@ -1964,6 +1964,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
if (cfgParseOptionValid(config->command, config->commandRole, optionId))
{
config->option[optionId].valid = true;
config->option[optionId].dataType = cfgParseOptionDataType(optionId);
config->option[optionId].group = parseRuleOption[optionId].group;
config->option[optionId].groupId = parseRuleOption[optionId].groupId;
}
@ -2085,7 +2086,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// Is the value set for this option?
bool optionSet =
parseOptionValue->found && (optionType == cfgOptTypeBoolean || !parseOptionValue->negate) &&
parseOptionValue->found && (optionType == cfgOptTypeBoolean || !parseOptionValue->negate) &&
!parseOptionValue->reset;
// Initialize option value and set negate and reset flag
@ -2115,7 +2116,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// If depend value is not set
ASSERT(config->option[dependId].index != NULL);
if (config->option[dependId].index[optionListIdx].value == NULL)
if (!config->option[dependId].index[optionListIdx].set)
{
THROW_FMT(
OptionInvalidError, "option '%s' not valid without option '%s'",
@ -2164,8 +2165,9 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
OptionInvalidError,
strZ(
strNewFmt(
"option '%s' not valid without option '%s'%s", cfgParseOptionKeyIdxName(optionId, optionKeyIdx),
strZ(dependOptionName), strZ(errorValue))));
"option '%s' not valid without option '%s'%s",
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), strZ(dependOptionName),
strZ(errorValue))));
}
pckReadFree(filter);
@ -2176,24 +2178,23 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// Is the option set?
if (optionSet)
{
configOptionValue->set = true;
configOptionValue->source = parseOptionValue->source;
if (optionType == cfgOptTypeBoolean)
{
configOptionValue->value = !parseOptionValue->negate ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
configOptionValue->value.boolean = !parseOptionValue->negate;
}
else if (optionType == cfgOptTypeHash)
{
Variant *value = NULL;
KeyValue *value = NULL;
MEM_CONTEXT_BEGIN(config->memContext)
{
value = varNewKv(kvNew());
value = kvNew();
}
MEM_CONTEXT_END();
KeyValue *keyValue = varKv(value);
for (unsigned int listIdx = 0; listIdx < strLstSize(parseOptionValue->valueList); listIdx++)
{
const char *pair = strZ(strLstGet(parseOptionValue->valueList, listIdx));
@ -2207,16 +2208,16 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
}
kvPut(keyValue, VARSTR(strNewZN(pair, (size_t)(equal - pair))), VARSTRZ(equal + 1));
kvPut(value, VARSTR(strNewZN(pair, (size_t)(equal - pair))), VARSTRZ(equal + 1));
}
configOptionValue->value = value;
configOptionValue->value.keyValue = value;
}
else if (optionType == cfgOptTypeList)
{
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->value = varNewVarLst(varLstNewStrLst(parseOptionValue->valueList));
configOptionValue->value.list = varLstNewStrLst(parseOptionValue->valueList);
}
MEM_CONTEXT_END();
}
@ -2224,55 +2225,40 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
{
String *value = strLstGet(parseOptionValue->valueList, 0);
const String *valueAllow = value;
int64_t valueInt64 = 0;
// Preserve original value to display
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->display = strDup(value);
}
MEM_CONTEXT_END();
// If a numeric type check that the value is valid
if (optionType == cfgOptTypeInteger || optionType == cfgOptTypeSize ||
optionType == cfgOptTypeTime)
{
// Preserve original value to display
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->display = strDup(value);
}
MEM_CONTEXT_END();
// Check that the value can be converted
TRY_BEGIN()
{
if (optionType == cfgOptTypeInteger)
switch (optionType)
{
MEM_CONTEXT_BEGIN(config->memContext)
case cfgOptTypeInteger:
configOptionValue->value.integer = cvtZToInt64(strZ(value));
break;
case cfgOptTypeSize:
configOptionValue->value.integer = (int64_t)convertToByte(value);
valueAllow = varStrForce(VARINT64(configOptionValue->value.integer));
break;
default:
{
configOptionValue->value = varNewInt64(cvtZToInt64(strZ(value)));
ASSERT(optionType == cfgOptTypeTime);
configOptionValue->value.integer = (int64_t)(cvtZToDouble(
strZ(value)) * MSEC_PER_SEC);
break;
}
MEM_CONTEXT_END();
valueInt64 = varInt64(configOptionValue->value);
}
else if (optionType == cfgOptTypeSize)
{
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->value = varNewInt64((int64_t)convertToByte(value));
}
MEM_CONTEXT_END();
valueInt64 = varInt64(configOptionValue->value);
valueAllow = varStrForce(configOptionValue->value);
}
else
{
ASSERT(optionType == cfgOptTypeTime);
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->value = varNewInt64(
(int64_t)(cvtZToDouble(strZ(value)) * MSEC_PER_SEC));
}
MEM_CONTEXT_END();
valueInt64 = varInt64(configOptionValue->value);
}
}
CATCH_ANY()
@ -2285,7 +2271,8 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
if (cfgParseOptionalRule(
&optionalRules, parseRuleOptionalTypeAllowRange, config->command, optionId) &&
(valueInt64 < optionalRules.allowRangeMin || valueInt64 > optionalRules.allowRangeMax))
(configOptionValue->value.integer < optionalRules.allowRangeMin ||
configOptionValue->value.integer > optionalRules.allowRangeMax))
{
THROW_FMT(
OptionInvalidValueError, "'%s' is out of range for '%s' option", strZ(value),
@ -2295,6 +2282,9 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// Else if string make sure it is valid
else
{
// Set string value to display value
configOptionValue->value.string = configOptionValue->display;
// Empty strings are not valid
if (strSize(value) == 0)
{
@ -2324,14 +2314,17 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// If the path ends with a / we'll strip it off (unless the value is just /)
if (strEndsWithZ(value, "/") && strSize(value) != 1)
{
strTrunc(value, (int)strSize(value) - 1);
}
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->value = varNewStr(value);
// Reset string value since it was modified
MEM_CONTEXT_BEGIN(config->memContext)
{
configOptionValue->value.string = strDup(value);
}
MEM_CONTEXT_END();
}
}
MEM_CONTEXT_END();
}
// If the option has an allow list then check it
@ -2382,7 +2375,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
while (pckReadNext(allowList))
{
if (parseRuleValueInt[pckReadU32P(allowList)] == valueInt64)
if (parseRuleValueInt[pckReadU32P(allowList)] == configOptionValue->value.integer)
{
allowListFound = true;
break;
@ -2418,6 +2411,7 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
// If the option has a default
if (found)
{
configOptionValue->set = true;
configOptionValue->value = optionalRules.defaultValue;
}
// Else error if option is required and help was not requested

View File

@ -22,6 +22,18 @@ typedef enum
cfgOptTypeTime, // Time in seconds, e.g. 23, 1.5
} ConfigOptionType;
/***********************************************************************************************************************************
Underlying data type for an option
***********************************************************************************************************************************/
typedef enum
{
cfgOptDataTypeBoolean, // Boolean
cfgOptDataTypeHash, // Hash
cfgOptDataTypeInteger, // Signed 64-bit integer
cfgOptDataTypeList, // List
cfgOptDataTypeString, // String
} ConfigOptionDataType;
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
@ -76,6 +88,9 @@ bool cfgParseOptionSecure(ConfigOption optionId);
// Option data type
ConfigOptionType cfgParseOptionType(ConfigOption optionId);
// Get the underlying data type for an option
ConfigOptionDataType cfgParseOptionDataType(ConfigOption optionId);
// Is the option required?
bool cfgParseOptionRequired(ConfigCommand commandId, ConfigOption optionId);

View File

@ -33,7 +33,7 @@ configOptionProtocol(PackRead *const param, ProtocolServer *const server)
CfgParseOptionResult option = cfgParseOptionP(pckReadStrP(param));
CHECK(option.found);
varLstAdd(optionList, varDup(cfgOptionIdx(option.id, cfgOptionKeyToIdx(option.id, option.keyIdx + 1))));
varLstAdd(optionList, varDup(cfgOptionIdxVar(option.id, cfgOptionKeyToIdx(option.id, option.keyIdx + 1))));
}
protocolServerDataPut(server, pckWriteStrP(protocolPackNew(), jsonFromVar(varNewVarLst(optionList))));

View File

@ -163,7 +163,7 @@ protocolLocalParam(ProtocolStorageType protocolStorageType, unsigned int hostIdx
// Only enable file logging on the local when requested
kvPut(
optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_FILE),
cfgOptionBool(cfgOptLogSubprocess) ? cfgOption(cfgOptLogLevelFile) : VARSTRDEF("off"));
cfgOptionBool(cfgOptLogSubprocess) ? VARSTR(cfgOptionStr(cfgOptLogLevelFile)) : VARSTRDEF("off"));
// Always output errors on stderr for debugging purposes
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_STDERR), VARSTRDEF("error"));
@ -514,7 +514,7 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
{
kvPut(
optionReplace, VARSTRZ(cfgOptionIdxName(optionId, 0)),
cfgOptionIdxSource(optionId, hostIdx) != cfgSourceDefault ? cfgOptionIdx(optionId, hostIdx) : NULL);
cfgOptionIdxSource(optionId, hostIdx) != cfgSourceDefault ? cfgOptionIdxVar(optionId, hostIdx) : NULL);
}
remove = true;
@ -551,7 +551,7 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
// Only enable file logging on the remote when requested
kvPut(
optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_FILE),
cfgOptionBool(cfgOptLogSubprocess) ? cfgOption(cfgOptLogLevelFile) : VARSTRDEF("off"));
cfgOptionBool(cfgOptLogSubprocess) ? VARSTR(cfgOptionStr(cfgOptLogLevelFile)) : VARSTRDEF("off"));
// Always output errors on stderr for debugging purposes
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_STDERR), VARSTRDEF("error"));

View File

@ -1425,7 +1425,7 @@ testRun(void)
TEST_RESULT_BOOL(cfgCommandHelp(), true, "help is set");
TEST_RESULT_INT(cfgCommand(), cfgCmdBackup, "command is backup");
TEST_RESULT_BOOL(cfgOptionValid(cfgOptPgPath), true, "pg1-path is valid");
TEST_RESULT_PTR(cfgOption(cfgOptPgPath), NULL, "pg1-path is not set");
TEST_RESULT_PTR(cfgOptionVar(cfgOptPgPath), NULL, "pg1-path is not set");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("command argument valid");
@ -1633,6 +1633,7 @@ testRun(void)
TEST_RESULT_UINT(cfgOptionGroupIdxDefault(cfgOptGrpPg), 0, "pg1 is default");
TEST_RESULT_UINT(cfgOptionGroupIdxToKey(cfgOptGrpPg, 1), 2, "pg2 is index 2");
TEST_RESULT_STR_Z(cfgOptionStr(cfgOptPgPath), "/path/to/db", "default pg-path");
TEST_RESULT_STR_Z(varStr(cfgOptionVar(cfgOptPgPath)), "/path/to/db", "default pg-path as variant");
TEST_RESULT_BOOL(cfgOptionGroupValid(cfgOptGrpPg), true, "pg group is valid");
TEST_RESULT_UINT(cfgOptionGroupIdxTotal(cfgOptGrpPg), 3, "pg1, pg2, and pg256 are set");
TEST_RESULT_BOOL(cfgOptionIdxBool(cfgOptPgLocal, 1), true, "pg2-local is set");
@ -1652,6 +1653,7 @@ testRun(void)
TEST_RESULT_INT(cfgOptionSource(cfgOptStartFast), cfgSourceConfig, "start-fast is config param");
TEST_RESULT_UINT(cfgOptionIdxTotal(cfgOptDelta), 1, "delta not indexed");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptDelta), true, "delta not set");
TEST_RESULT_BOOL(varBool(cfgOptionVar(cfgOptDelta)), true, "delta as variant");
TEST_RESULT_INT(cfgOptionSource(cfgOptDelta), cfgSourceConfig, "delta is source config");
TEST_RESULT_BOOL(cfgOptionTest(cfgOptArchiveCheck), false, "archive-check is not set");
TEST_RESULT_BOOL(cfgOptionTest(cfgOptArchiveCopy), false, "archive-copy is not set");
@ -1659,6 +1661,7 @@ testRun(void)
TEST_RESULT_STR_Z(cfgOptionDisplay(cfgOptRepoHardlink), "true", "repo-hardlink display is true");
TEST_RESULT_INT(cfgOptionSource(cfgOptRepoHardlink), cfgSourceConfig, "repo-hardlink is source config");
TEST_RESULT_UINT(cfgOptionUInt(cfgOptRepoRetentionFull), 55, "repo-retention-full is set");
TEST_RESULT_INT(varInt64(cfgOptionVar(cfgOptRepoRetentionFull)), 55, "repo-retention-full as variant");
TEST_RESULT_INT(cfgOptionInt(cfgOptCompressLevel), 3, "compress-level is set");
TEST_RESULT_INT(cfgOptionSource(cfgOptCompressLevel), cfgSourceConfig, "compress-level is source config");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptBackupStandby), false, "backup-standby not is set");
@ -1696,7 +1699,7 @@ testRun(void)
TEST_ERROR(cfgOptionDisplay(cfgOptTarget), AssertError, "option 'target' is not valid for the current command");
TEST_ERROR(cfgOptionLst(cfgOptDbInclude), AssertError, "option 'db-include' is not valid for the current command");
TEST_ERROR(cfgOptionKv(cfgOptPgPath), AssertError, "option 'pg1-path' is type 4 but 3 was requested");
TEST_ERROR(cfgOptionKv(cfgOptPgPath), AssertError, "option 'pg1-path' is type 4 but 1 was requested");
TEST_RESULT_VOID(cfgOptionInvalidate(cfgOptPgPath), "invalidate pg-path");
TEST_RESULT_BOOL(cfgOptionValid(cfgOptPgPath), false, "pg-path no longer valid");
@ -1747,7 +1750,7 @@ testRun(void)
TEST_RESULT_INT(cfgOptionIdxInt64(cfgOptBufferSize, 0), 2097152, "buffer-size is set to bytes from MB");
TEST_RESULT_STR_Z(cfgOptionDisplay(cfgOptBufferSize), "2MB", "buffer-size display is 2MB");
TEST_RESULT_INT(cfgOptionSource(cfgOptBufferSize), cfgSourceParam, "buffer-size is source config");
TEST_RESULT_PTR(cfgOption(cfgOptSpoolPath), NULL, "spool-path is not set");
TEST_RESULT_PTR(cfgOptionVar(cfgOptSpoolPath), NULL, "spool-path is not set");
TEST_RESULT_INT(cfgOptionSource(cfgOptSpoolPath), cfgSourceDefault, "spool-path is source default");
// -------------------------------------------------------------------------------------------------------------------------
@ -1778,7 +1781,7 @@ testRun(void)
TEST_RESULT_STR_Z(jsonFromVar(varNewVarLst(cfgCommandJobRetry())), "[0,15000]", "default job retry");
const VariantList *includeList = NULL;
TEST_ASSIGN(includeList, cfgOptionLst(cfgOptDbInclude), "get db include options");
TEST_ASSIGN(includeList, varVarLst(cfgOptionVar(cfgOptDbInclude)), "get db include options");
TEST_RESULT_STR_Z(varStr(varLstGet(includeList, 0)), "abc", "check db include option");
TEST_RESULT_STR_Z(varStr(varLstGet(includeList, 1)), "def", "check db include option");
@ -1798,9 +1801,11 @@ testRun(void)
TEST_RESULT_PTR(cfgCommandJobRetry(), NULL, "no job retries");
const KeyValue *recoveryKv = NULL;
TEST_RESULT_PTR(cfgOptionKvNull(cfgOptLinkMap), NULL, "link map is null");
TEST_RESULT_PTR(cfgOptionIdxKvNull(cfgOptLinkMap, 0), NULL, "link map is null");
TEST_ASSIGN(recoveryKv, cfgOptionKv(cfgOptRecoveryOption), "get recovery options");
TEST_RESULT_STR_Z(varStr(kvGet(recoveryKv, VARSTRDEF("a"))), "b", "check recovery option");
TEST_ASSIGN(recoveryKv, cfgOptionIdxKv(cfgOptRecoveryOption, 0), "get recovery options");
TEST_ASSIGN(recoveryKv, varKv(cfgOptionIdxVar(cfgOptRecoveryOption, 0)), "get recovery options");
TEST_RESULT_STR_Z(varStr(kvGet(recoveryKv, VARSTRDEF("c"))), "de=fg hi", "check recovery option");
TEST_RESULT_BOOL(cfgLockRequired(), false, "restore command does not require lock");
@ -1858,22 +1863,19 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("cfgOptionSet() and cfgOptionIdxSet()");
TEST_RESULT_VOID(cfgOptionSet(cfgOptForce, cfgSourceParam, VARINT(1)), "set force true");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptForce), true, "check force");
TEST_RESULT_VOID(cfgOptionSet(cfgOptForce, cfgSourceParam, VARBOOL(false)), "set force false");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptForce), false, "check force");
TEST_RESULT_VOID(cfgOptionSet(cfgOptForce, cfgSourceParam, VARBOOL(false)), "set boolean");
TEST_RESULT_BOOL(cfgOptionBool(cfgOptForce), false, "check boolean");
TEST_RESULT_VOID(cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, VARINT64(1000)), "set protocol-timeout to 1");
TEST_RESULT_UINT(cfgOptionUInt64(cfgOptProtocolTimeout), 1000, "check protocol-timeout");
TEST_RESULT_VOID(cfgOptionSet(cfgOptProtocolTimeout, cfgSourceParam, VARINT64(2200)), "set protocol-timeout to 2.2");
TEST_RESULT_UINT(cfgOptionUInt64(cfgOptProtocolTimeout), 2200, "check protocol-timeout");
TEST_RESULT_VOID(cfgOptionSet(cfgOptProcessMax, cfgSourceParam, VARINT(50)), "set process-max to 50");
TEST_RESULT_INT(cfgOptionInt(cfgOptProcessMax), 50, "check process-max");
TEST_RESULT_VOID(cfgOptionSet(cfgOptProcessMax, cfgSourceParam, VARINT64(51)), "set process-max to 51");
TEST_RESULT_INT(cfgOptionInt(cfgOptProcessMax), 51, "check process-max");
TEST_ERROR(cfgOptionSet(cfgOptDbInclude, cfgSourceParam, VARINT(1)), AssertError, "set not available for option type 3");
TEST_ERROR(
cfgOptionSet(cfgOptDbInclude, cfgSourceParam, VARINT(1)), AssertError, "set not available for option data type 3");
TEST_ERROR(
cfgOptionIdxSet(cfgOptPgPath, 0, cfgSourceParam, VARINT(1)), AssertError,