1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-15 01:04:37 +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:
David Steele
2021-11-03 15:23:08 -04:00
committed by GitHub
parent 1b93a77236
commit 038abaa71d
15 changed files with 285 additions and 219 deletions

View File

@ -64,6 +64,24 @@
</release-item> </release-item>
</release-development-list> </release-development-list>
</release-core-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>
<release date="2021-11-01" version="2.36" title="Minor Bug Fixes and Improvements"> <release date="2021-11-01" version="2.36" title="Minor Bug Fixes and Improvements">

View File

@ -39,6 +39,7 @@ SRCS_BUILD = \
common/type/xml.c \ common/type/xml.c \
common/user.c \ common/user.c \
common/wait.c \ common/wait.c \
config/common.c \
storage/posix/read.c \ storage/posix/read.c \
storage/posix/storage.c \ storage/posix/storage.c \
storage/posix/write.c \ storage/posix/write.c \

View File

@ -581,19 +581,19 @@ option:
buffer-size: buffer-size:
section: global section: global
type: size type: size
default: 1048576 default: 1MiB
allow-list: allow-list:
- 16384 - 16KiB
- 32768 - 32KiB
- 65536 - 64KiB
- 131072 - 128KiB
- 262144 - 256KiB
- 524288 - 512KiB
- 1048576 - 1MiB
- 2097152 - 2MiB
- 4194304 - 4MiB
- 8388608 - 8MiB
- 16777216 - 16MiB
command: command:
archive-get: {} archive-get: {}
archive-push: {} archive-push: {}
@ -1032,8 +1032,8 @@ option:
archive-get-queue-max: archive-get-queue-max:
section: global section: global
type: size type: size
default: 134217728 default: 128MiB
allow-range: [0, 4503599627370496] allow-range: [0, 4PiB]
command: command:
archive-get: {} archive-get: {}
command-role: command-role:
@ -1054,7 +1054,7 @@ option:
section: global section: global
type: size type: size
required: false required: false
allow-range: [0, 4503599627370496] allow-range: [0, 4PiB]
command: command:
archive-push: {} archive-push: {}
command-role: command-role:
@ -1148,8 +1148,8 @@ option:
manifest-save-threshold: manifest-save-threshold:
section: global section: global
type: size type: size
default: 1073741824 default: 1GiB
allow-range: [1, 1099511627776] allow-range: [1, 1TiB]
command: command:
backup: {} backup: {}
command-role: command-role:

View File

@ -7,6 +7,7 @@ Render Configuration Data
#include "common/log.h" #include "common/log.h"
#include "common/type/convert.h" #include "common/type/convert.h"
#include "config/common.h"
#include "storage/posix/storage.h" #include "storage/posix/storage.h"
#include "build/common/render.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)) 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 else
{ {
@ -515,7 +520,9 @@ bldCfgRenderValueAdd(
const String *const optType, const String *const value, StringList *const ruleDataList, StringList *const ruleStrList) const String *const optType, const String *const value, StringList *const ruleDataList, StringList *const ruleStrList)
{ {
if (strEq(optType, OPT_TYPE_TIME_STR)) 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 else
strLstAddIfMissing(ruleDataList, value); strLstAddIfMissing(ruleDataList, value);

View File

@ -132,12 +132,13 @@
<text> <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>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> </text>
<example>32K</example> <example>2MiB</example>
</config-key> </config-key>
<!-- CONFIG - GENERAL SECTION - CMD KEY --> <!-- CONFIG - GENERAL SECTION - CMD KEY -->
@ -1138,10 +1139,11 @@
<text> <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>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> </text>
<example>5G</example> <example>8GiB</example>
</config-key> </config-key>
<!-- CONFIG - BACKUP SECTION - EXPIRE-AUTO --> <!-- CONFIG - BACKUP SECTION - EXPIRE-AUTO -->
@ -1225,10 +1227,11 @@
<text> <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>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> </text>
<example>1073741824</example> <example>1GiB</example>
</config-key> </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>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> </text>
<example>1GB</example> <example>1TiB</example>
</config-key> </config-key>
<!-- ======================================================================================================= --> <!-- ======================================================================================================= -->

View File

@ -150,25 +150,23 @@ helpRenderText(const String *text, const bool internal, size_t indent, bool inde
Helper function for helpRender() to output values as strings Helper function for helpRender() to output values as strings
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
static const String * static const String *
helpRenderValue(const Variant *value, ConfigOptionType type) helpRenderValue(const ConfigOption optionId, const unsigned int optionIdx)
{ {
FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(VARIANT, value); FUNCTION_LOG_PARAM(ENUM, optionId);
FUNCTION_LOG_PARAM(ENUM, type); FUNCTION_LOG_PARAM(UINT, optionIdx);
FUNCTION_LOG_END(); FUNCTION_LOG_END();
const String *result = NULL; const String *result = NULL;
if (value != NULL) if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
{ {
if (varType(value) == varTypeBool) const Variant *const value = cfgOptionIdxVar(optionId, optionIdx);
ASSERT(value != NULL);
switch (varType(value))
{ {
if (varBool(value)) case varTypeKeyValue:
result = Y_STR;
else
result = N_STR;
}
else if (varType(value) == varTypeKeyValue)
{ {
String *resultTemp = strNew(); String *resultTemp = strNew();
@ -186,8 +184,10 @@ helpRenderValue(const Variant *value, ConfigOptionType type)
} }
result = resultTemp; result = resultTemp;
break;
} }
else if (varType(value) == varTypeVariantList)
case varTypeVariantList:
{ {
String *resultTemp = strNew(); String *resultTemp = strNew();
@ -202,9 +202,13 @@ helpRenderValue(const Variant *value, ConfigOptionType type)
} }
result = resultTemp; result = resultTemp;
break;
}
default:
result = cfgOptionIdxDisplay(optionId, optionIdx);
break;
} }
else
result = cfgOptionDisplayVar(value, type);
} }
FUNCTION_LOG_RETURN_CONST(STRING, result); FUNCTION_LOG_RETURN_CONST(STRING, result);
@ -450,10 +454,7 @@ helpRender(const Buffer *const helpData)
// Output current and default values if they exist // Output current and default values if they exist
const String *defaultValue = cfgOptionDefault(optionId); const String *defaultValue = cfgOptionDefault(optionId);
const String *value = NULL; const String *value = helpRenderValue(optionId, 0);
if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
value = helpRenderValue(cfgOptionIdxVar(optionId, 0), cfgParseOptionType(optionId));
if (value != NULL || defaultValue != NULL) if (value != NULL || defaultValue != NULL)
{ {
@ -517,10 +518,7 @@ helpRender(const Buffer *const helpData)
// Output current and default values if they exist // Output current and default values if they exist
const String *defaultValue = cfgOptionDefault(option.id); const String *defaultValue = cfgOptionDefault(option.id);
const String *value = NULL; const String *value = helpRenderValue(option.id, 0);
if (cfgOptionIdxSource(option.id, 0) != cfgSourceDefault)
value = helpRenderValue(cfgOptionIdxVar(option.id, 0), cfgParseOptionType(option.id));
if (value != NULL || defaultValue != NULL) if (value != NULL || defaultValue != NULL)
{ {

121
src/config/common.c Normal file
View 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
View 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

View File

@ -114,7 +114,11 @@ cfgExecParam(ConfigCommand commandId, ConfigCommandRole commandRoleId, const Key
else else
{ {
valueList = strLstNew(); valueList = strLstNew();
strLstAdd(valueList, cfgOptionDisplayVar(value, cfgParseOptionType(optionId)));
strLstAdd(
valueList,
exists ? cfgOptionDisplayVar(value, cfgParseOptionType(optionId)) :
cfgOptionIdxDisplay(optionId, optionIdx));
} }
// Output options and values // Output options and values

View File

@ -16,12 +16,12 @@ static const StringPub parseRuleValueStr[] =
PARSE_RULE_STRPUB("/var/log/pgbackrest"), PARSE_RULE_STRPUB("/var/log/pgbackrest"),
PARSE_RULE_STRPUB("/var/spool/pgbackrest"), PARSE_RULE_STRPUB("/var/spool/pgbackrest"),
PARSE_RULE_STRPUB("1"), PARSE_RULE_STRPUB("1"),
PARSE_RULE_STRPUB("1048576"), PARSE_RULE_STRPUB("128MiB"),
PARSE_RULE_STRPUB("1073741824"),
PARSE_RULE_STRPUB("134217728"),
PARSE_RULE_STRPUB("15"), PARSE_RULE_STRPUB("15"),
PARSE_RULE_STRPUB("1800"), PARSE_RULE_STRPUB("1800"),
PARSE_RULE_STRPUB("1830"), PARSE_RULE_STRPUB("1830"),
PARSE_RULE_STRPUB("1GiB"),
PARSE_RULE_STRPUB("1MiB"),
PARSE_RULE_STRPUB("2"), PARSE_RULE_STRPUB("2"),
PARSE_RULE_STRPUB("3"), PARSE_RULE_STRPUB("3"),
PARSE_RULE_STRPUB("443"), PARSE_RULE_STRPUB("443"),
@ -63,12 +63,12 @@ typedef enum
parseRuleValStrQT_FS_var_FS_log_FS_pgbackrest_QT, parseRuleValStrQT_FS_var_FS_log_FS_pgbackrest_QT,
parseRuleValStrQT_FS_var_FS_spool_FS_pgbackrest_QT, parseRuleValStrQT_FS_var_FS_spool_FS_pgbackrest_QT,
parseRuleValStrQT_1_QT, parseRuleValStrQT_1_QT,
parseRuleValStrQT_1048576_QT, parseRuleValStrQT_128MiB_QT,
parseRuleValStrQT_1073741824_QT,
parseRuleValStrQT_134217728_QT,
parseRuleValStrQT_15_QT, parseRuleValStrQT_15_QT,
parseRuleValStrQT_1800_QT, parseRuleValStrQT_1800_QT,
parseRuleValStrQT_1830_QT, parseRuleValStrQT_1830_QT,
parseRuleValStrQT_1GiB_QT,
parseRuleValStrQT_1MiB_QT,
parseRuleValStrQT_2_QT, parseRuleValStrQT_2_QT,
parseRuleValStrQT_3_QT, parseRuleValStrQT_3_QT,
parseRuleValStrQT_443_QT, parseRuleValStrQT_443_QT,
@ -848,7 +848,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
PARSE_RULE_OPTIONAL_DEFAULT PARSE_RULE_OPTIONAL_DEFAULT
( (
PARSE_RULE_VAL_INT(parseRuleValInt134217728), 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_OPTIONAL_DEFAULT
( (
PARSE_RULE_VAL_INT(parseRuleValInt1048576), 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_OPTIONAL_DEFAULT
( (
PARSE_RULE_VAL_INT(parseRuleValInt1073741824), PARSE_RULE_VAL_INT(parseRuleValInt1073741824),
PARSE_RULE_VAL_STR(parseRuleValStrQT_1073741824_QT), PARSE_RULE_VAL_STR(parseRuleValStrQT_1GiB_QT),
), ),
), ),
), ),

View File

@ -16,6 +16,7 @@ Command and Option Parse
#include "common/macro.h" #include "common/macro.h"
#include "common/memContext.h" #include "common/memContext.h"
#include "common/regExp.h" #include "common/regExp.h"
#include "config/common.h"
#include "config/config.intern.h" #include "config/config.intern.h"
#include "config/parse.h" #include "config/parse.h"
#include "version.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)); 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) Load the configuration file(s)
@ -2240,16 +2143,14 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
break; break;
case cfgOptTypeSize: case cfgOptTypeSize:
configOptionValue->value.integer = (int64_t)convertToByte(value); configOptionValue->value.integer = cfgParseSize(value);
valueAllow = varStrForce(VARINT64(configOptionValue->value.integer));
break; break;
default: default:
{ {
ASSERT(optionType == cfgOptTypeTime); ASSERT(optionType == cfgOptTypeTime);
configOptionValue->value.integer = (int64_t)(cvtZToDouble( configOptionValue->value.integer = cfgParseTime(value);
strZ(value)) * MSEC_PER_SEC);
break; break;
} }
} }

View File

@ -386,6 +386,7 @@ unit:
depend: depend:
- command/backup/pageChecksum - command/backup/pageChecksum
- common/lock - common/lock
- config/common
- config/config - config/config
- config/parse - config/parse
- config/exec - config/exec
@ -483,6 +484,7 @@ unit:
total: 6 total: 6
coverage: coverage:
- config/common
- config/config - config/config
- config/parse - config/parse
- config/parse.auto: noCode - config/parse.auto: noCode
@ -770,7 +772,7 @@ unit:
# ---------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------
- name: help - name: help
total: 5 total: 4
coverage: coverage:
- command/help/help - command/help/help

View File

@ -119,17 +119,6 @@ testRun(void)
"two paragraphs, indent first, internal"); "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()")) if (testBegin("helpRender()"))
{ {
@ -222,7 +211,7 @@ testRun(void)
"General Options:\n" "General Options:\n"
"\n" "\n"
" --buffer-size buffer size for I/O operations\n" " --buffer-size buffer size for I/O operations\n"
" [current=32768, default=1048576]\n" " [current=32768, default=1MiB]\n"
" --cmd pgBackRest command\n" " --cmd pgBackRest command\n"
" [default=/path/to/pgbackrest]\n" " [default=/path/to/pgbackrest]\n"
" --cmd-ssh SSH client command [default=ssh]\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" "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" "memory, e.g. gz compression may use an additional 256KiB of memory.\n"
"\n" "\n"
"Size can be entered in bytes (default) or KB, MB, GB, TB, or PB where the\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 32k (or\n" "multiplier is a power of 1024. For example, the case-insensitive value 5GiB (or\n"
"32KB) can be used instead of 32768.\n" "5GB, 5g) can be used instead of 5368709120. Fractional values such as 2.5GiB\n"
"are not allowed, use 2560MiB instead.\n"
"\n" "\n"
"Allowed values, in bytes, are 16384, 32768, 65536, 131072, 262144, 524288,\n" "Allowed values are 16KiB, 32KiB, 64KiB, 128KiB, 256KiB, 512KiB, 1MiB, 2MiB,\n"
"1048576, 2097152, 4194304, 8388608, and 16777216.\n", "4MiB, 8MiB, and 16MiB.\n",
helpVersion)); helpVersion));
argList = strLstNew(); argList = strLstNew();
@ -386,13 +376,13 @@ testRun(void)
strLstAddZ(argList, "archive-push"); strLstAddZ(argList, "archive-push");
strLstAddZ(argList, "buffer-size"); strLstAddZ(argList, "buffer-size");
TEST_RESULT_VOID(testCfgLoad(argList), "help for archive-push command, buffer-size option"); 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 // 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_VOID(testCfgLoad(argList), "help for archive-push command, buffer-size option");
TEST_RESULT_STR( 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"); TEST_TITLE("deprecated host option names");

View File

@ -18,6 +18,7 @@ testRun(void)
StringList *argList = strLstNew(); StringList *argList = strLstNew();
hrnCfgArgRawZ(argList, cfgOptStanza, "test1"); hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "5"); hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "5");
hrnCfgArgRawZ(argList, cfgOptBufferSize, "64KiB");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo"); hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 1, TEST_PATH "/db path"); hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 1, TEST_PATH "/db path");
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 2, "/db2"); hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 2, "/db2");
@ -34,14 +35,14 @@ testRun(void)
TEST_RESULT_STRLST_Z( TEST_RESULT_STRLST_Z(
cfgExecParam(cfgCmdArchiveGet, cfgCmdRoleAsync, NULL, false, true), 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" "--pg1-path=\"" TEST_PATH "/db path\"\n--pg2-path=/db2\n--repo1-path=" TEST_PATH "/repo\n--stanza=test1\n"
"archive-get:async\n", "archive-get:async\n",
"exec archive-get -> archive-get:async"); "exec archive-get -> archive-get:async");
TEST_RESULT_STRLST_Z( TEST_RESULT_STRLST_Z(
cfgExecParam(cfgCmdBackup, cfgCmdRoleMain, NULL, false, false), 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", "--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"); "exec archive-get -> backup");

View File

@ -593,14 +593,15 @@ testRun(void)
// ***************************************************************************************************************************** // *****************************************************************************************************************************
if (testBegin("convertToByte()")) if (testBegin("convertToByte()"))
{ {
TEST_ERROR(sizeQualifierToMultiplier('w'), AssertError, "'w' is not a valid size qualifier"); TEST_ERROR(cfgParseSizeQualifier('w'), AssertError, "'w' is not a valid size qualifier");
TEST_RESULT_UINT(convertToByte(STRDEF("10B")), 10, "10B"); TEST_RESULT_INT(cfgParseSize(STRDEF("10B")), 10, "10B");
TEST_RESULT_UINT(convertToByte(STRDEF("1k")), 1024, "1k"); TEST_RESULT_INT(cfgParseSize(STRDEF("1k")), 1024, "1k");
TEST_RESULT_UINT(convertToByte(STRDEF("5G")), (uint64_t)5 * 1024 * 1024 * 1024, "5G"); TEST_RESULT_INT(cfgParseSize(STRDEF("1KiB")), 1024, "1KiB");
TEST_RESULT_UINT(convertToByte(STRDEF("3Tb")), (uint64_t)3 * 1024 * 1024 * 1024 * 1024, "3Tb"); TEST_RESULT_INT(cfgParseSize(STRDEF("5G")), (uint64_t)5 * 1024 * 1024 * 1024, "5G");
TEST_RESULT_UINT(convertToByte(STRDEF("11")), 11, "11 - no qualifier, default bytes"); TEST_RESULT_INT(cfgParseSize(STRDEF("3Tb")), (uint64_t)3 * 1024 * 1024 * 1024 * 1024, "3Tb");
TEST_RESULT_UINT(convertToByte(STRDEF("4pB")), 4503599627370496, "4pB"); TEST_RESULT_INT(cfgParseSize(STRDEF("11")), 11, "11 - no qualifier, default bytes");
TEST_RESULT_UINT(convertToByte(STRDEF("15MB")), (uint64_t)15 * 1024 * 1024, "15MB"); 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_BACKREST_EXE);
strLstAddZ(argList, TEST_COMMAND_BACKUP); strLstAddZ(argList, TEST_COMMAND_BACKUP);
hrnCfgArgRawZ(argList, cfgOptStanza, "db"); hrnCfgArgRawZ(argList, cfgOptStanza, "db");
hrnCfgArgRawZ(argList, cfgOptManifestSaveThreshold, "9999999999999999999p"); hrnCfgArgRawZ(argList, cfgOptManifestSaveThreshold, "999999999999999999p");
TEST_ERROR( TEST_ERROR(
configParse(storageTest, strLstSize(argList), strLstPtr(argList), false), OptionInvalidValueError, 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"); TEST_TITLE("value missing");