1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-03-03 14:52:21 +02:00

Refactor option and option group config structs.

This allows individual structs to be assigned to variables to make the code easier to read and perhaps a bit more efficient.
This commit is contained in:
David Steele 2022-01-10 17:00:58 -05:00
parent aeecb500f5
commit 7c627c12b7
3 changed files with 112 additions and 94 deletions

View File

@ -47,6 +47,7 @@
<commit subject="Dynamically allocate index to key index map."/>
<commit subject="Replace cfgOptionGroupIdxToKey() with cfgOptionGroupName()."/>
<commit subject="Improve implementation of cfgOptionIdxName()."/>
<commit subject="Refactor option and option group config structs."/>
<release-item-contributor-list>
<release-item-contributor id="david.steele"/>

View File

@ -251,23 +251,21 @@ cfgOptionGroupName(const ConfigOptionGroup groupId, const unsigned int groupIdx)
ASSERT(groupIdx < configLocal->optionGroup[groupId].indexTotal);
// Generate display names for the group the first time one is requested
if (configLocal->optionGroup[groupId].indexDisplay == NULL)
ConfigOptionGroupData *const group = &configLocal->optionGroup[groupId];
if (group->indexDisplay == NULL)
{
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
configLocal->optionGroup[groupId].indexDisplay = memNew(
sizeof(String *) * configLocal->optionGroup[groupId].indexTotal);
group->indexDisplay = memNew(sizeof(String *) * group->indexTotal);
for (unsigned int groupIdx = 0; groupIdx < configLocal->optionGroup[groupId].indexTotal; groupIdx++)
{
configLocal->optionGroup[groupId].indexDisplay[groupIdx] = strNewFmt(
"%s%u", configLocal->optionGroup[groupId].name, configLocal->optionGroup[groupId].indexMap[groupIdx] + 1);
}
for (unsigned int groupIdx = 0; groupIdx < group->indexTotal; groupIdx++)
group->indexDisplay[groupIdx] = strNewFmt("%s%u", group->name, group->indexMap[groupIdx] + 1);
}
MEM_CONTEXT_END();
}
FUNCTION_TEST_RETURN(strZ(configLocal->optionGroup[groupId].indexDisplay[groupIdx]));
FUNCTION_TEST_RETURN(strZ(group->indexDisplay[groupIdx]));
}
/**********************************************************************************************************************************/
@ -391,8 +389,9 @@ cfgOptionIdxDefault(ConfigOption optionId)
ASSERT(
!configLocal->option[optionId].group || configLocal->optionGroup[configLocal->option[optionId].groupId].indexDefaultExists);
FUNCTION_TEST_RETURN(
configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexDefault : 0);
const ConfigOptionData *const option = &configLocal->option[optionId];
FUNCTION_TEST_RETURN(option->group ? configLocal->optionGroup[option->groupId].indexDefault : 0);
}
/**********************************************************************************************************************************/
@ -406,8 +405,9 @@ cfgOptionIdxTotal(ConfigOption optionId)
ASSERT(configLocal != NULL);
ASSERT(optionId < CFG_OPTION_TOTAL);
FUNCTION_TEST_RETURN(
configLocal->option[optionId].group ? configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal : 1);
const ConfigOptionData *const option = &configLocal->option[optionId];
FUNCTION_TEST_RETURN(option->group ? configLocal->optionGroup[option->groupId].indexTotal : 1);
}
/**********************************************************************************************************************************/
@ -421,10 +421,12 @@ cfgOptionDefault(ConfigOption optionId)
ASSERT(configLocal != NULL);
ASSERT(optionId < CFG_OPTION_TOTAL);
if (configLocal->option[optionId].defaultValue == NULL)
configLocal->option[optionId].defaultValue = cfgParseOptionDefault(cfgCommand(), optionId);
ConfigOptionData *const option = &configLocal->option[optionId];
FUNCTION_TEST_RETURN(configLocal->option[optionId].defaultValue);
if (option->defaultValue == NULL)
option->defaultValue = cfgParseOptionDefault(cfgCommand(), optionId);
FUNCTION_TEST_RETURN(option->defaultValue);
}
void
@ -446,16 +448,19 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
defaultValue = varDup(defaultValue);
// Set the default value
configLocal->option[optionId].defaultValue = varStr(defaultValue);
ConfigOptionData *const option = &configLocal->option[optionId];
option->defaultValue = varStr(defaultValue);
// Copy the value to option indexes that are marked as default so the default can be retrieved quickly
for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
{
if (configLocal->option[optionId].index[optionIdx].source == cfgSourceDefault)
ConfigOptionValue *const optionValue = &option->index[optionIdx];
if (optionValue->source == cfgSourceDefault)
{
configLocal->option[optionId].index[optionIdx].set = true;
configLocal->option[optionId].index[optionIdx].value.string = varStr(defaultValue);
configLocal->option[optionId].index[optionIdx].display = NULL;
optionValue->set = true;
optionValue->value.string = varStr(defaultValue);
optionValue->display = NULL;
}
}
}
@ -665,34 +670,33 @@ cfgOptionIdxName(ConfigOption optionId, unsigned int optionIdx)
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
// If an indexed option
if (configLocal->option[optionId].group)
ConfigOptionData *const option = &configLocal->option[optionId];
if (option->group)
{
const ConfigOptionGroupData *const group = &configLocal->optionGroup[option->groupId];
// Generate indexed names for the option the first time one is requested
if (configLocal->option[optionId].indexName == NULL)
if (option->indexName == NULL)
{
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
const unsigned int indexTotal = configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal;
option->indexName = memNew(sizeof(String *) * group->indexTotal);
configLocal->option[optionId].indexName = memNew(sizeof(String *) * indexTotal);
for (unsigned int optionIdx = 0; optionIdx < indexTotal; optionIdx++)
for (unsigned int optionIdx = 0; optionIdx < group->indexTotal; optionIdx++)
{
configLocal->option[optionId].indexName[optionIdx] = strNewFmt(
"%s%u%s", configLocal->optionGroup[configLocal->option[optionId].groupId].name,
configLocal->optionGroup[configLocal->option[optionId].groupId].indexMap[optionIdx] + 1,
configLocal->option[optionId].name +
strlen(configLocal->optionGroup[configLocal->option[optionId].groupId].name));
option->indexName[optionIdx] = strNewFmt(
"%s%u%s", group->name, group->indexMap[optionIdx] + 1, option->name + strlen(group->name));
}
}
MEM_CONTEXT_END();
}
FUNCTION_TEST_RETURN(strZ(configLocal->option[optionId].indexName[optionIdx]));
FUNCTION_TEST_RETURN(strZ(option->indexName[optionIdx]));
}
// Else not indexed
FUNCTION_TEST_RETURN(configLocal->option[optionId].name);
FUNCTION_TEST_RETURN(option->name);
}
/**********************************************************************************************************************************/
@ -778,15 +782,16 @@ cfgOptionIdxInternal(
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 ConfigOptionValue *const result = &configLocal->option[optionId].index[optionIdx];
ConfigOptionData *const option = &configLocal->option[optionId];
ConfigOptionValue *const result = &option->index[optionIdx];
if (result->set)
{
if (configLocal->option[optionId].dataType != typeRequested)
if (option->dataType != typeRequested)
{
THROW_FMT(
AssertError, "option '%s' is type %u but %u was requested", cfgOptionIdxName(optionId, optionIdx),
configLocal->option[optionId].dataType, typeRequested);
option->dataType, typeRequested);
}
}
// Else check the option is allowed to be NULL
@ -810,31 +815,35 @@ cfgOptionIdxVar(const ConfigOption optionId, const unsigned int optionIdx)
(configLocal->option[optionId].group && optionIdx <
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
if (configLocal->option[optionId].index[optionIdx].set)
const ConfigOptionData *const option = &configLocal->option[optionId];
if (option->index[optionIdx].set)
{
switch (configLocal->option[optionId].dataType)
const ConfigOptionValueType *const optionValueType = &option->index[optionIdx].value;
switch (option->dataType)
{
case cfgOptDataTypeBoolean:
FUNCTION_TEST_RETURN(varNewBool(configLocal->option[optionId].index[optionIdx].value.boolean));
FUNCTION_TEST_RETURN(varNewBool(optionValueType->boolean));
case cfgOptDataTypeHash:
FUNCTION_TEST_RETURN(varNewKv(kvDup(configLocal->option[optionId].index[optionIdx].value.keyValue)));
FUNCTION_TEST_RETURN(varNewKv(kvDup(optionValueType->keyValue)));
case cfgOptDataTypeInteger:
FUNCTION_TEST_RETURN(varNewInt64(configLocal->option[optionId].index[optionIdx].value.integer));
FUNCTION_TEST_RETURN(varNewInt64(optionValueType->integer));
case cfgOptDataTypeList:
FUNCTION_TEST_RETURN(varNewVarLst(configLocal->option[optionId].index[optionIdx].value.list));
FUNCTION_TEST_RETURN(varNewVarLst(optionValueType->list));
case cfgOptDataTypeStringId:
FUNCTION_TEST_RETURN(varNewUInt64(configLocal->option[optionId].index[optionIdx].value.stringId));
FUNCTION_TEST_RETURN(varNewUInt64(optionValueType->stringId));
default:
ASSERT(configLocal->option[optionId].dataType == cfgOptDataTypeString);
ASSERT(option->dataType == cfgOptDataTypeString);
break;
}
FUNCTION_TEST_RETURN(varNewStr(configLocal->option[optionId].index[optionIdx].value.string));
FUNCTION_TEST_RETURN(varNewStr(optionValueType->string));
}
FUNCTION_TEST_RETURN(NULL);
@ -1016,19 +1025,23 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
configLocal->optionGroup[configLocal->option[optionId].groupId].indexTotal));
// Set the source
configLocal->option[optionId].index[optionIdx].source = source;
ConfigOptionData *const option = &configLocal->option[optionId];
ConfigOptionValue *const optionValue = &option->index[optionIdx];
optionValue->source = source;
// Only set value if it is not null
ConfigOptionValueType *const optionValueType = &optionValue->value;
if (value != NULL)
{
switch (configLocal->option[optionId].dataType)
switch (option->dataType)
{
case cfgOptDataTypeBoolean:
configLocal->option[optionId].index[optionIdx].value.boolean = varBool(value);
optionValueType->boolean = varBool(value);
break;
case cfgOptDataTypeInteger:
configLocal->option[optionId].index[optionIdx].value.integer = varInt64(value);
optionValueType->integer = varInt64(value);
break;
case cfgOptDataTypeString:
@ -1037,7 +1050,7 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
{
MEM_CONTEXT_BEGIN(configLocal->memContext)
{
configLocal->option[optionId].index[optionIdx].value.string = strDup(varStr(value));
optionValueType->string = strDup(varStr(value));
}
MEM_CONTEXT_END();
}
@ -1053,29 +1066,30 @@ cfgOptionIdxSet(ConfigOption optionId, unsigned int optionIdx, ConfigSource sour
case cfgOptDataTypeStringId:
{
if (varType(value) == varTypeUInt64)
configLocal->option[optionId].index[optionIdx].value.stringId = varUInt64(value);
optionValueType->stringId = varUInt64(value);
else
configLocal->option[optionId].index[optionIdx].value.stringId = strIdFromStr(varStr(value));
optionValueType->stringId = strIdFromStr(varStr(value));
break;
}
default:
THROW_FMT(AssertError, "set not available for option data type %u", configLocal->option[optionId].dataType);
THROW_FMT(AssertError, "set not available for option data type %u", option->dataType);
}
configLocal->option[optionId].index[optionIdx].set = true;
optionValue->set = true;
}
else
{
configLocal->option[optionId].index[optionIdx].set = false;
optionValue->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;
// Setting string to NULL suffices to set the other pointers in the union to NULL.
optionValueType->string = NULL;
}
// Clear the display value, which will be generated when needed
configLocal->option[optionId].index[optionIdx].display = NULL;
optionValue->display = NULL;
FUNCTION_TEST_RETURN_VOID();
}

View File

@ -16,26 +16,51 @@ The general-purpose functions for querying the current configuration are found i
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.
***********************************************************************************************************************************/
// Group options that are related to allow valid and test checks across all options in the group
typedef struct ConfigOptionGroupData
{
const char *name; // Name
bool valid; // Is option group valid for the current command?
unsigned int indexTotal; // Total number of indexes with values in option group
bool indexDefaultExists; // Is there a default index for non-indexed functions?
unsigned int indexDefault; // Default index (usually 0)
unsigned int *indexMap; // List of index to key index mappings
const String **indexDisplay; // List of index display names
} ConfigOptionGroupData;
// Option data
typedef union ConfigOptionValueType
{
bool boolean; // Boolean
int64_t integer; // Integer
const KeyValue *keyValue; // KeyValue
const VariantList *list; // VariantList
const String *string; // String
StringId stringId; // StringId
bool boolean; // Boolean
int64_t integer; // Integer
const KeyValue *keyValue; // KeyValue
const VariantList *list; // VariantList
const String *string; // String
StringId stringId; // StringId
} 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.
ConfigOptionValueType value; // Option value
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.
ConfigOptionValueType value; // Option value
} ConfigOptionValue;
typedef struct ConfigOptionData
{
const char *name; // Name
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)
const String **indexName; // Index names (e.g. repo1-path, repo2-path)
} ConfigOptionData;
typedef struct Config
{
MemContext *memContext; // Mem context for config data
@ -53,30 +78,8 @@ typedef struct Config
LogLevel logLevelDefault; // Default log level
StringList *paramList; // Parameters passed to the command (if any)
// Group options that are related together to allow valid and test checks across all options in the group
struct
{
const char *name; // Name
bool valid; // Is option group valid for the current command?
unsigned int indexTotal; // Total number of indexes with values in option group
bool indexDefaultExists; // Is there a default index for non-indexed functions?
unsigned int indexDefault; // Default index (usually 0)
unsigned int *indexMap; // List of index to key index mappings
const String **indexDisplay; // List of index display names
} optionGroup[CFG_OPTION_GROUP_TOTAL];
// Option data
struct
{
const char *name; // Name
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)
const String **indexName; // Index names (e.g. repo1-path, repo2-path)
} option[CFG_OPTION_TOTAL];
ConfigOptionGroupData optionGroup[CFG_OPTION_GROUP_TOTAL]; // Option group data
ConfigOptionData option[CFG_OPTION_TOTAL]; // Option data
} Config;
/***********************************************************************************************************************************