mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Display size option default and allowed values with appropriate units.
Size option default and allowed values were displayed in bytes, which was confusing for the user. This also lays the groundwork for adding units to time options. Move option parsing functions into a common module so they can be used from the build module.
This commit is contained in:
parent
1b93a77236
commit
038abaa71d
@ -64,6 +64,24 @@
|
||||
</release-item>
|
||||
</release-development-list>
|
||||
</release-core-list>
|
||||
|
||||
<release-doc-list>
|
||||
<release-improvement-list>
|
||||
<release-item>
|
||||
<commit subject="Centralize logic to build value lists during config rendering."/>
|
||||
<commit subject="Display size option default and allowed values with appropriate units.">
|
||||
<github-pull-request id="1557"/>
|
||||
</commit>
|
||||
|
||||
<release-item-contributor-list>
|
||||
<release-item-contributor id="david.steele"/>
|
||||
<release-item-reviewer id="reid.thompson"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Display size option default and allowed values with appropriate units.</p>
|
||||
</release-item>
|
||||
</release-improvement-list>
|
||||
</release-doc-list>
|
||||
</release>
|
||||
|
||||
<release date="2021-11-01" version="2.36" title="Minor Bug Fixes and Improvements">
|
||||
|
@ -39,6 +39,7 @@ SRCS_BUILD = \
|
||||
common/type/xml.c \
|
||||
common/user.c \
|
||||
common/wait.c \
|
||||
config/common.c \
|
||||
storage/posix/read.c \
|
||||
storage/posix/storage.c \
|
||||
storage/posix/write.c \
|
||||
|
@ -581,19 +581,19 @@ option:
|
||||
buffer-size:
|
||||
section: global
|
||||
type: size
|
||||
default: 1048576
|
||||
default: 1MiB
|
||||
allow-list:
|
||||
- 16384
|
||||
- 32768
|
||||
- 65536
|
||||
- 131072
|
||||
- 262144
|
||||
- 524288
|
||||
- 1048576
|
||||
- 2097152
|
||||
- 4194304
|
||||
- 8388608
|
||||
- 16777216
|
||||
- 16KiB
|
||||
- 32KiB
|
||||
- 64KiB
|
||||
- 128KiB
|
||||
- 256KiB
|
||||
- 512KiB
|
||||
- 1MiB
|
||||
- 2MiB
|
||||
- 4MiB
|
||||
- 8MiB
|
||||
- 16MiB
|
||||
command:
|
||||
archive-get: {}
|
||||
archive-push: {}
|
||||
@ -1032,8 +1032,8 @@ option:
|
||||
archive-get-queue-max:
|
||||
section: global
|
||||
type: size
|
||||
default: 134217728
|
||||
allow-range: [0, 4503599627370496]
|
||||
default: 128MiB
|
||||
allow-range: [0, 4PiB]
|
||||
command:
|
||||
archive-get: {}
|
||||
command-role:
|
||||
@ -1054,7 +1054,7 @@ option:
|
||||
section: global
|
||||
type: size
|
||||
required: false
|
||||
allow-range: [0, 4503599627370496]
|
||||
allow-range: [0, 4PiB]
|
||||
command:
|
||||
archive-push: {}
|
||||
command-role:
|
||||
@ -1148,8 +1148,8 @@ option:
|
||||
manifest-save-threshold:
|
||||
section: global
|
||||
type: size
|
||||
default: 1073741824
|
||||
allow-range: [1, 1099511627776]
|
||||
default: 1GiB
|
||||
allow-range: [1, 1TiB]
|
||||
command:
|
||||
backup: {}
|
||||
command-role:
|
||||
|
@ -7,6 +7,7 @@ Render Configuration Data
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/type/convert.h"
|
||||
#include "config/common.h"
|
||||
#include "storage/posix/storage.h"
|
||||
|
||||
#include "build/common/render.h"
|
||||
@ -383,7 +384,11 @@ bldCfgRenderScalar(const String *const scalar, const String *const optType)
|
||||
|
||||
if (strEq(optType, OPT_TYPE_TIME_STR))
|
||||
{
|
||||
value = (int64_t)(cvtZToDouble(strZ(scalar)) * 1000);
|
||||
value = cfgParseTime(scalar);
|
||||
}
|
||||
else if (strEq(optType, OPT_TYPE_SIZE_STR))
|
||||
{
|
||||
value = cfgParseSize(scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -515,7 +520,9 @@ bldCfgRenderValueAdd(
|
||||
const String *const optType, const String *const value, StringList *const ruleDataList, StringList *const ruleStrList)
|
||||
{
|
||||
if (strEq(optType, OPT_TYPE_TIME_STR))
|
||||
strLstAddIfMissing(ruleDataList, strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(value)) * 1000)));
|
||||
strLstAddIfMissing(ruleDataList, strNewFmt("%" PRId64, cfgParseTime(value)));
|
||||
else if (strEq(optType, OPT_TYPE_SIZE_STR))
|
||||
strLstAddIfMissing(ruleDataList, strNewFmt("%" PRId64, cfgParseSize(value)));
|
||||
else
|
||||
strLstAddIfMissing(ruleDataList, value);
|
||||
|
||||
|
@ -132,12 +132,13 @@
|
||||
<text>
|
||||
<p>Buffer size used for copy, compress, encrypt, and other operations. The number of buffers used depends on options and each operation may use additional memory, e.g. <id>gz</id> compression may use an additional 256KiB of memory.</p>
|
||||
|
||||
<p>Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the multiplier is a power of 1024. For example, the case-insensitive value 32k (or 32KB) can be used instead of 32768.</p>
|
||||
<!-- Be sure to update other copies of this block when modifying -->
|
||||
<p>Size can be entered in bytes (default) or KiB, MiB, GiB, TiB, or PiB where the multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or 5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB are not allowed, use 2560MiB instead.</p>
|
||||
|
||||
<p>Allowed values, in bytes, are <id>16384</id>, <id>32768</id>, <id>65536</id>, <id>131072</id>, <id>262144</id>, <id>524288</id>, <id>1048576</id>, <id>2097152</id>, <id>4194304</id>, <id>8388608</id>, and <id>16777216</id>.</p>
|
||||
<p>Allowed values are <id>16KiB</id>, <id>32KiB</id>, <id>64KiB</id>, <id>128KiB</id>, <id>256KiB</id>, <id>512KiB</id>, <id>1MiB</id>, <id>2MiB</id>, <id>4MiB</id>, <id>8MiB</id>, and <id>16MiB</id>.</p>
|
||||
</text>
|
||||
|
||||
<example>32K</example>
|
||||
<example>2MiB</example>
|
||||
</config-key>
|
||||
|
||||
<!-- CONFIG - GENERAL SECTION - CMD KEY -->
|
||||
@ -1138,10 +1139,11 @@
|
||||
<text>
|
||||
<p>Defines how often the manifest will be saved during a backup. Saving the manifest is important because it stores the checksums and allows the resume function to work efficiently. The actual threshold used is 1% of the backup size or <setting>manifest-save-threshold</setting>, whichever is greater.</p>
|
||||
|
||||
<p>Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the multiplier is a power of 1024.</p>
|
||||
<!-- Be sure to update other copies of this block when modifying -->
|
||||
<p>Size can be entered in bytes (default) or KiB, MiB, GiB, TiB, or PiB where the multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or 5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB are not allowed, use 2560MiB instead.</p>
|
||||
</text>
|
||||
|
||||
<example>5G</example>
|
||||
<example>8GiB</example>
|
||||
</config-key>
|
||||
|
||||
<!-- CONFIG - BACKUP SECTION - EXPIRE-AUTO -->
|
||||
@ -1225,10 +1227,11 @@
|
||||
<text>
|
||||
<p>Specifies the maximum size of the <cmd>archive-get</cmd> queue when <br-option>archive-async</br-option> is enabled. The queue is stored in the <br-option>spool-path</br-option> and is used to speed providing WAL to <postgres/>.</p>
|
||||
|
||||
<p>Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the multiplier is a power of 1024.</p>
|
||||
<!-- Be sure to update other copies of this block when modifying -->
|
||||
<p>Size can be entered in bytes (default) or KiB, MiB, GiB, TiB, or PiB where the multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or 5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB are not allowed, use 2560MiB instead.</p>
|
||||
</text>
|
||||
|
||||
<example>1073741824</example>
|
||||
<example>1GiB</example>
|
||||
</config-key>
|
||||
|
||||
<!-- ======================================================================================================= -->
|
||||
@ -1262,10 +1265,11 @@
|
||||
|
||||
<p>The purpose of this feature is to prevent the log volume from filling up at which point Postgres will stop completely. Better to lose the backup than have <postgres/> go down.</p>
|
||||
|
||||
<p>Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the multiplier is a power of 1024.</p>
|
||||
<!-- Be sure to update other copies of this block when modifying -->
|
||||
<p>Size can be entered in bytes (default) or KiB, MiB, GiB, TiB, or PiB where the multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or 5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB are not allowed, use 2560MiB instead.</p>
|
||||
</text>
|
||||
|
||||
<example>1GB</example>
|
||||
<example>1TiB</example>
|
||||
</config-key>
|
||||
|
||||
<!-- ======================================================================================================= -->
|
||||
|
@ -150,61 +150,65 @@ helpRenderText(const String *text, const bool internal, size_t indent, bool inde
|
||||
Helper function for helpRender() to output values as strings
|
||||
***********************************************************************************************************************************/
|
||||
static const String *
|
||||
helpRenderValue(const Variant *value, ConfigOptionType type)
|
||||
helpRenderValue(const ConfigOption optionId, const unsigned int optionIdx)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(VARIANT, value);
|
||||
FUNCTION_LOG_PARAM(ENUM, type);
|
||||
FUNCTION_LOG_PARAM(ENUM, optionId);
|
||||
FUNCTION_LOG_PARAM(UINT, optionIdx);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
const String *result = NULL;
|
||||
|
||||
if (value != NULL)
|
||||
if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
|
||||
{
|
||||
if (varType(value) == varTypeBool)
|
||||
{
|
||||
if (varBool(value))
|
||||
result = Y_STR;
|
||||
else
|
||||
result = N_STR;
|
||||
}
|
||||
else if (varType(value) == varTypeKeyValue)
|
||||
{
|
||||
String *resultTemp = strNew();
|
||||
const Variant *const value = cfgOptionIdxVar(optionId, optionIdx);
|
||||
ASSERT(value != NULL);
|
||||
|
||||
const KeyValue *optionKv = varKv(value);
|
||||
const VariantList *keyList = kvKeyList(optionKv);
|
||||
|
||||
for (unsigned int keyIdx = 0; keyIdx < varLstSize(keyList); keyIdx++)
|
||||
switch (varType(value))
|
||||
{
|
||||
case varTypeKeyValue:
|
||||
{
|
||||
if (keyIdx != 0)
|
||||
strCatZ(resultTemp, ", ");
|
||||
String *resultTemp = strNew();
|
||||
|
||||
strCatFmt(
|
||||
resultTemp, "%s=%s", strZ(varStr(varLstGet(keyList, keyIdx))),
|
||||
strZ(varStrForce(kvGet(optionKv, varLstGet(keyList, keyIdx)))));
|
||||
const KeyValue *optionKv = varKv(value);
|
||||
const VariantList *keyList = kvKeyList(optionKv);
|
||||
|
||||
for (unsigned int keyIdx = 0; keyIdx < varLstSize(keyList); keyIdx++)
|
||||
{
|
||||
if (keyIdx != 0)
|
||||
strCatZ(resultTemp, ", ");
|
||||
|
||||
strCatFmt(
|
||||
resultTemp, "%s=%s", strZ(varStr(varLstGet(keyList, keyIdx))),
|
||||
strZ(varStrForce(kvGet(optionKv, varLstGet(keyList, keyIdx)))));
|
||||
}
|
||||
|
||||
result = resultTemp;
|
||||
break;
|
||||
}
|
||||
|
||||
result = resultTemp;
|
||||
}
|
||||
else if (varType(value) == varTypeVariantList)
|
||||
{
|
||||
String *resultTemp = strNew();
|
||||
|
||||
const VariantList *list = varVarLst(value);
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(list); listIdx++)
|
||||
case varTypeVariantList:
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCatZ(resultTemp, ", ");
|
||||
String *resultTemp = strNew();
|
||||
|
||||
strCatFmt(resultTemp, "%s", strZ(varStr(varLstGet(list, listIdx))));
|
||||
const VariantList *list = varVarLst(value);
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < varLstSize(list); listIdx++)
|
||||
{
|
||||
if (listIdx != 0)
|
||||
strCatZ(resultTemp, ", ");
|
||||
|
||||
strCatFmt(resultTemp, "%s", strZ(varStr(varLstGet(list, listIdx))));
|
||||
}
|
||||
|
||||
result = resultTemp;
|
||||
break;
|
||||
}
|
||||
|
||||
result = resultTemp;
|
||||
default:
|
||||
result = cfgOptionIdxDisplay(optionId, optionIdx);
|
||||
break;
|
||||
}
|
||||
else
|
||||
result = cfgOptionDisplayVar(value, type);
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN_CONST(STRING, result);
|
||||
@ -450,10 +454,7 @@ helpRender(const Buffer *const helpData)
|
||||
|
||||
// Output current and default values if they exist
|
||||
const String *defaultValue = cfgOptionDefault(optionId);
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
|
||||
value = helpRenderValue(cfgOptionIdxVar(optionId, 0), cfgParseOptionType(optionId));
|
||||
const String *value = helpRenderValue(optionId, 0);
|
||||
|
||||
if (value != NULL || defaultValue != NULL)
|
||||
{
|
||||
@ -517,10 +518,7 @@ helpRender(const Buffer *const helpData)
|
||||
|
||||
// Output current and default values if they exist
|
||||
const String *defaultValue = cfgOptionDefault(option.id);
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionIdxSource(option.id, 0) != cfgSourceDefault)
|
||||
value = helpRenderValue(cfgOptionIdxVar(option.id, 0), cfgParseOptionType(option.id));
|
||||
const String *value = helpRenderValue(option.id, 0);
|
||||
|
||||
if (value != NULL || defaultValue != NULL)
|
||||
{
|
||||
|
121
src/config/common.c
Normal file
121
src/config/common.c
Normal file
@ -0,0 +1,121 @@
|
||||
/***********************************************************************************************************************************
|
||||
Configuration Common
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/regExp.h"
|
||||
#include "common/time.h"
|
||||
#include "config/common.h"
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
// Helper to get the multiplier based on the qualifier
|
||||
static int64_t
|
||||
cfgParseSizeQualifier(const char qualifier)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(CHAR, qualifier);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
int64_t result;
|
||||
|
||||
switch (qualifier)
|
||||
{
|
||||
case 'b':
|
||||
result = 1;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
result = 1024;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
result = 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
result = 1024 * 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
result = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
result = 1024LL * 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
|
||||
default:
|
||||
THROW_FMT(AssertError, "'%c' is not a valid size qualifier", qualifier);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
int64_t
|
||||
cfgParseSize(const String *const value)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING, value);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(value != NULL);
|
||||
|
||||
// Lowercase the value
|
||||
String *valueLower = strLower(strDup(value));
|
||||
|
||||
// Match the value against possible values
|
||||
if (regExpMatchOne(STRDEF("^[0-9]+(kib|kb|k|mib|mb|m|gib|gb|g|tib|tb|t|pib|pb|p|b)*$"), valueLower))
|
||||
{
|
||||
// Get the character array and size
|
||||
const char *strArray = strZ(valueLower);
|
||||
size_t size = strSize(valueLower);
|
||||
int chrPos = -1;
|
||||
|
||||
// If there is a 'b' on the end, then see if the previous character is a number
|
||||
if (strArray[size - 1] == 'b')
|
||||
{
|
||||
// If the previous character is a number, then the letter to look at is 'b' which is the last position else it is in the
|
||||
// next to last position (e.g. kb - so the 'k' is the position of interest). Only need to test for <= 9 since the regex
|
||||
// enforces the format. Also allow an 'i' before the 'b'.
|
||||
if (strArray[size - 2] <= '9')
|
||||
chrPos = (int)(size - 1);
|
||||
else if (strArray[size - 2] == 'i')
|
||||
chrPos = (int)(size - 3);
|
||||
else
|
||||
chrPos = (int)(size - 2);
|
||||
}
|
||||
// Else if there is no 'b' at the end but the last position is not a number then it must be one of the letters, e.g. 'k'
|
||||
else if (strArray[size - 1] > '9')
|
||||
chrPos = (int)(size - 1);
|
||||
|
||||
int64_t multiplier = 1;
|
||||
|
||||
// If a letter was found calculate multiplier, else do nothing since assumed value is already in bytes
|
||||
if (chrPos != -1)
|
||||
{
|
||||
multiplier = cfgParseSizeQualifier(strArray[chrPos]);
|
||||
|
||||
// Remove any letters
|
||||
strTrunc(valueLower, chrPos);
|
||||
}
|
||||
|
||||
// Convert string to bytes
|
||||
FUNCTION_TEST_RETURN(cvtZToInt64(strZ(valueLower)) * multiplier);
|
||||
}
|
||||
|
||||
THROW_FMT(FormatError, "value '%s' is not valid", strZ(value));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
int64_t
|
||||
cfgParseTime(const String *const value)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING, value);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(value != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN((int64_t)(cvtZToDouble(strZ(value)) * MSEC_PER_SEC));
|
||||
}
|
18
src/config/common.h
Normal file
18
src/config/common.h
Normal file
@ -0,0 +1,18 @@
|
||||
/***********************************************************************************************************************************
|
||||
Configuration Common
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef CONFIG_COMMON_H
|
||||
#define CONFIG_COMMON_H
|
||||
|
||||
#include "common/type/string.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Parse option size, e.g. 23m
|
||||
int64_t cfgParseSize(const String *value);
|
||||
|
||||
// Parse option time, e.g. 900
|
||||
int64_t cfgParseTime(const String *value);
|
||||
|
||||
#endif
|
@ -114,7 +114,11 @@ cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const Key
|
||||
else
|
||||
{
|
||||
valueList = strLstNew();
|
||||
strLstAdd(valueList, cfgOptionDisplayVar(value, cfgParseOptionType(optionId)));
|
||||
|
||||
strLstAdd(
|
||||
valueList,
|
||||
exists ? cfgOptionDisplayVar(value, cfgParseOptionType(optionId)) :
|
||||
cfgOptionIdxDisplay(optionId, optionIdx));
|
||||
}
|
||||
|
||||
// Output options and values
|
||||
|
@ -16,12 +16,12 @@ static const StringPub parseRuleValueStr[] =
|
||||
PARSE_RULE_STRPUB("/var/log/pgbackrest"),
|
||||
PARSE_RULE_STRPUB("/var/spool/pgbackrest"),
|
||||
PARSE_RULE_STRPUB("1"),
|
||||
PARSE_RULE_STRPUB("1048576"),
|
||||
PARSE_RULE_STRPUB("1073741824"),
|
||||
PARSE_RULE_STRPUB("134217728"),
|
||||
PARSE_RULE_STRPUB("128MiB"),
|
||||
PARSE_RULE_STRPUB("15"),
|
||||
PARSE_RULE_STRPUB("1800"),
|
||||
PARSE_RULE_STRPUB("1830"),
|
||||
PARSE_RULE_STRPUB("1GiB"),
|
||||
PARSE_RULE_STRPUB("1MiB"),
|
||||
PARSE_RULE_STRPUB("2"),
|
||||
PARSE_RULE_STRPUB("3"),
|
||||
PARSE_RULE_STRPUB("443"),
|
||||
@ -63,12 +63,12 @@ typedef enum
|
||||
parseRuleValStrQT_FS_var_FS_log_FS_pgbackrest_QT,
|
||||
parseRuleValStrQT_FS_var_FS_spool_FS_pgbackrest_QT,
|
||||
parseRuleValStrQT_1_QT,
|
||||
parseRuleValStrQT_1048576_QT,
|
||||
parseRuleValStrQT_1073741824_QT,
|
||||
parseRuleValStrQT_134217728_QT,
|
||||
parseRuleValStrQT_128MiB_QT,
|
||||
parseRuleValStrQT_15_QT,
|
||||
parseRuleValStrQT_1800_QT,
|
||||
parseRuleValStrQT_1830_QT,
|
||||
parseRuleValStrQT_1GiB_QT,
|
||||
parseRuleValStrQT_1MiB_QT,
|
||||
parseRuleValStrQT_2_QT,
|
||||
parseRuleValStrQT_3_QT,
|
||||
parseRuleValStrQT_443_QT,
|
||||
@ -848,7 +848,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
|
||||
PARSE_RULE_OPTIONAL_DEFAULT
|
||||
(
|
||||
PARSE_RULE_VAL_INT(parseRuleValInt134217728),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_134217728_QT),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_128MiB_QT),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -1138,7 +1138,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
|
||||
PARSE_RULE_OPTIONAL_DEFAULT
|
||||
(
|
||||
PARSE_RULE_VAL_INT(parseRuleValInt1048576),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_1048576_QT),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_1MiB_QT),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -2896,7 +2896,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
|
||||
PARSE_RULE_OPTIONAL_DEFAULT
|
||||
(
|
||||
PARSE_RULE_VAL_INT(parseRuleValInt1073741824),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_1073741824_QT),
|
||||
PARSE_RULE_VAL_STR(parseRuleValStrQT_1GiB_QT),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -16,6 +16,7 @@ Command and Option Parse
|
||||
#include "common/macro.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "config/common.h"
|
||||
#include "config/config.intern.h"
|
||||
#include "config/parse.h"
|
||||
#include "version.h"
|
||||
@ -1142,104 +1143,6 @@ cfgParseOptionValid(ConfigCommand commandId, ConfigCommandRole commandRoleId, Co
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].commandRoleValid[commandRoleId] & ((uint32_t)1 << commandId));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Generate multiplier based on character
|
||||
***********************************************************************************************************************************/
|
||||
static uint64_t
|
||||
sizeQualifierToMultiplier(char qualifier)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(CHAR, qualifier);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
uint64_t result;
|
||||
|
||||
switch (qualifier)
|
||||
{
|
||||
case 'b':
|
||||
result = 1;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
result = 1024;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
result = 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
result = 1024 * 1024 * 1024;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
result = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
result = 1024LL * 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
|
||||
default:
|
||||
THROW_FMT(AssertError, "'%c' is not a valid size qualifier", qualifier);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
convertToByte(const String *value)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(STRING, value);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(value != NULL);
|
||||
|
||||
// Lowercase the value
|
||||
String *valueLower = strLower(strDup(value));
|
||||
|
||||
// Match the value against possible values
|
||||
if (regExpMatchOne(STRDEF("^[0-9]+(kb|k|mb|m|gb|g|tb|t|pb|p|b)*$"), valueLower))
|
||||
{
|
||||
// Get the character array and size
|
||||
const char *strArray = strZ(valueLower);
|
||||
size_t size = strSize(valueLower);
|
||||
int chrPos = -1;
|
||||
|
||||
// If there is a 'b' on the end, then see if the previous character is a number
|
||||
if (strArray[size - 1] == 'b')
|
||||
{
|
||||
// If the previous character is a number, then the letter to look at is 'b' which is the last position else it is in the
|
||||
// next to last position (e.g. kb - so the 'k' is the position of interest). Only need to test for <= 9 since the regex
|
||||
// enforces the format.
|
||||
if (strArray[size - 2] <= '9')
|
||||
chrPos = (int)(size - 1);
|
||||
else
|
||||
chrPos = (int)(size - 2);
|
||||
}
|
||||
// else if there is no 'b' at the end but the last position is not a number then it must be one of the letters, e.g. 'k'
|
||||
else if (strArray[size - 1] > '9')
|
||||
chrPos = (int)(size - 1);
|
||||
|
||||
uint64_t multiplier = 1;
|
||||
|
||||
// If a letter was found calculate multiplier, else do nothing since assumed value is already in bytes
|
||||
if (chrPos != -1)
|
||||
{
|
||||
multiplier = sizeQualifierToMultiplier(strArray[chrPos]);
|
||||
|
||||
// Remove any letters
|
||||
strTrunc(valueLower, chrPos);
|
||||
}
|
||||
|
||||
// Convert string to bytes
|
||||
FUNCTION_TEST_RETURN(cvtZToUInt64(strZ(valueLower)) * multiplier);
|
||||
}
|
||||
else
|
||||
THROW_FMT(FormatError, "value '%s' is not valid", strZ(value));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Load the configuration file(s)
|
||||
|
||||
@ -2240,16 +2143,14 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
break;
|
||||
|
||||
case cfgOptTypeSize:
|
||||
configOptionValue->value.integer = (int64_t)convertToByte(value);
|
||||
valueAllow = varStrForce(VARINT64(configOptionValue->value.integer));
|
||||
configOptionValue->value.integer = cfgParseSize(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(optionType == cfgOptTypeTime);
|
||||
|
||||
configOptionValue->value.integer = (int64_t)(cvtZToDouble(
|
||||
strZ(value)) * MSEC_PER_SEC);
|
||||
configOptionValue->value.integer = cfgParseTime(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -386,6 +386,7 @@ unit:
|
||||
depend:
|
||||
- command/backup/pageChecksum
|
||||
- common/lock
|
||||
- config/common
|
||||
- config/config
|
||||
- config/parse
|
||||
- config/exec
|
||||
@ -483,6 +484,7 @@ unit:
|
||||
total: 6
|
||||
|
||||
coverage:
|
||||
- config/common
|
||||
- config/config
|
||||
- config/parse
|
||||
- config/parse.auto: noCode
|
||||
@ -770,7 +772,7 @@ unit:
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------------
|
||||
- name: help
|
||||
total: 5
|
||||
total: 4
|
||||
|
||||
coverage:
|
||||
- command/help/help
|
||||
|
@ -119,17 +119,6 @@ testRun(void)
|
||||
"two paragraphs, indent first, internal");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("helpRenderValue()"))
|
||||
{
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(true), cfgOptTypeBoolean), "y", "boolean y");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewBool(false), cfgOptTypeBoolean), "n", "boolean n");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewStrZ("test-string"), cfgOptTypeString), "test-string", "string");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234), cfgOptTypeInteger), "1234", "int");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234000), cfgOptTypeTime), "1234", "time");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(NULL, cfgOptTypeString), NULL, "null");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("helpRender()"))
|
||||
{
|
||||
@ -222,7 +211,7 @@ testRun(void)
|
||||
"General Options:\n"
|
||||
"\n"
|
||||
" --buffer-size buffer size for I/O operations\n"
|
||||
" [current=32768, default=1048576]\n"
|
||||
" [current=32768, default=1MiB]\n"
|
||||
" --cmd pgBackRest command\n"
|
||||
" [default=/path/to/pgbackrest]\n"
|
||||
" --cmd-ssh SSH client command [default=ssh]\n"
|
||||
@ -372,12 +361,13 @@ testRun(void)
|
||||
"of buffers used depends on options and each operation may use additional\n"
|
||||
"memory, e.g. gz compression may use an additional 256KiB of memory.\n"
|
||||
"\n"
|
||||
"Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the\n"
|
||||
"multiplier is a power of 1024. For example, the case-insensitive value 32k (or\n"
|
||||
"32KB) can be used instead of 32768.\n"
|
||||
"Size can be entered in bytes (default) or KiB, MiB, GiB, TiB, or PiB where the\n"
|
||||
"multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or\n"
|
||||
"5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB\n"
|
||||
"are not allowed, use 2560MiB instead.\n"
|
||||
"\n"
|
||||
"Allowed values, in bytes, are 16384, 32768, 65536, 131072, 262144, 524288,\n"
|
||||
"1048576, 2097152, 4194304, 8388608, and 16777216.\n",
|
||||
"Allowed values are 16KiB, 32KiB, 64KiB, 128KiB, 256KiB, 512KiB, 1MiB, 2MiB,\n"
|
||||
"4MiB, 8MiB, and 16MiB.\n",
|
||||
helpVersion));
|
||||
|
||||
argList = strLstNew();
|
||||
@ -386,13 +376,13 @@ testRun(void)
|
||||
strLstAddZ(argList, "archive-push");
|
||||
strLstAddZ(argList, "buffer-size");
|
||||
TEST_RESULT_VOID(testCfgLoad(argList), "help for archive-push command, buffer-size option");
|
||||
TEST_RESULT_STR(helpRender(helpData), strNewFmt("%s\ndefault: 1048576\n", optionHelp), "check text");
|
||||
TEST_RESULT_STR(helpRender(helpData), strNewFmt("%s\ndefault: 1MiB\n", optionHelp), "check text");
|
||||
|
||||
// Set a current value
|
||||
hrnCfgArgRawZ(argList, cfgOptBufferSize, "32768");
|
||||
hrnCfgArgRawZ(argList, cfgOptBufferSize, "32k");
|
||||
TEST_RESULT_VOID(testCfgLoad(argList), "help for archive-push command, buffer-size option");
|
||||
TEST_RESULT_STR(
|
||||
helpRender(helpData), strNewFmt("%s\ncurrent: 32768\ndefault: 1048576\n", optionHelp), "check text, current value");
|
||||
helpRender(helpData), strNewFmt("%s\ncurrent: 32k\ndefault: 1MiB\n", optionHelp), "check text, current value");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("deprecated host option names");
|
||||
|
@ -18,6 +18,7 @@ testRun(void)
|
||||
StringList *argList = strLstNew();
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
|
||||
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "5");
|
||||
hrnCfgArgRawZ(argList, cfgOptBufferSize, "64KiB");
|
||||
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 1, TEST_PATH "/db path");
|
||||
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 2, "/db2");
|
||||
@ -34,14 +35,14 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_STRLST_Z(
|
||||
cfgExecParam(cfgCmdArchiveGet, cfgCmdRoleAsync, NULL, false, true),
|
||||
"--archive-async\n--no-config\n--exec-id=1-test\n--log-subprocess\n--reset-neutral-umask\n"
|
||||
"--archive-async\n--buffer-size=64KiB\n--no-config\n--exec-id=1-test\n--log-subprocess\n--reset-neutral-umask\n"
|
||||
"--pg1-path=\"" TEST_PATH "/db path\"\n--pg2-path=/db2\n--repo1-path=" TEST_PATH "/repo\n--stanza=test1\n"
|
||||
"archive-get:async\n",
|
||||
"exec archive-get -> archive-get:async");
|
||||
|
||||
TEST_RESULT_STRLST_Z(
|
||||
cfgExecParam(cfgCmdBackup, cfgCmdRoleMain, NULL, false, false),
|
||||
"--archive-timeout=5\n--no-config\n--exec-id=1-test\n--log-subprocess\n--reset-neutral-umask\n"
|
||||
"--archive-timeout=5\n--buffer-size=64KiB\n--no-config\n--exec-id=1-test\n--log-subprocess\n--reset-neutral-umask\n"
|
||||
"--pg1-path=" TEST_PATH "/db path\n--pg2-path=/db2\n--repo1-path=" TEST_PATH "/repo\n--stanza=test1\nbackup\n",
|
||||
"exec archive-get -> backup");
|
||||
|
||||
|
@ -593,14 +593,15 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("convertToByte()"))
|
||||
{
|
||||
TEST_ERROR(sizeQualifierToMultiplier('w'), AssertError, "'w' is not a valid size qualifier");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("10B")), 10, "10B");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("1k")), 1024, "1k");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("5G")), (uint64_t)5 * 1024 * 1024 * 1024, "5G");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("3Tb")), (uint64_t)3 * 1024 * 1024 * 1024 * 1024, "3Tb");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("11")), 11, "11 - no qualifier, default bytes");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("4pB")), 4503599627370496, "4pB");
|
||||
TEST_RESULT_UINT(convertToByte(STRDEF("15MB")), (uint64_t)15 * 1024 * 1024, "15MB");
|
||||
TEST_ERROR(cfgParseSizeQualifier('w'), AssertError, "'w' is not a valid size qualifier");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("10B")), 10, "10B");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("1k")), 1024, "1k");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("1KiB")), 1024, "1KiB");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("5G")), (uint64_t)5 * 1024 * 1024 * 1024, "5G");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("3Tb")), (uint64_t)3 * 1024 * 1024 * 1024 * 1024, "3Tb");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("11")), 11, "11 - no qualifier, default bytes");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("4pB")), 4503599627370496, "4pB");
|
||||
TEST_RESULT_INT(cfgParseSize(STRDEF("15MB")), (uint64_t)15 * 1024 * 1024, "15MB");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
@ -958,10 +959,10 @@ testRun(void)
|
||||
strLstAddZ(argList, TEST_BACKREST_EXE);
|
||||
strLstAddZ(argList, TEST_COMMAND_BACKUP);
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
|
||||
hrnCfgArgRawZ(argList, cfgOptManifestSaveThreshold, "9999999999999999999p");
|
||||
hrnCfgArgRawZ(argList, cfgOptManifestSaveThreshold, "999999999999999999p");
|
||||
TEST_ERROR(
|
||||
configParse(storageTest, strLstSize(argList), strLstPtr(argList), false), OptionInvalidValueError,
|
||||
"'9999999999999999999p' is out of range for 'manifest-save-threshold' option");
|
||||
"'999999999999999999p' is out of range for 'manifest-save-threshold' option");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("value missing");
|
||||
|
Loading…
Reference in New Issue
Block a user