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

Display time option defaults and allowed values with appropriate units.

Similar to size options in 038abaa7, time option defaults and allowed values were displayed in seconds, which could be confusing when the values were large.

The time options were not updated in 038abaa7 because it required removing the ability to do fractional seconds, e.g. 0.5 seconds. In theory this could cause breakage for users but it seems really unlikely. Fractional seconds are used in tests, however, so the tests have been changed to use milliseconds where required, e.g. 500ms.
This commit is contained in:
David Steele 2024-07-04 15:42:09 +07:00
parent df469471e3
commit 3a2266f327
10 changed files with 116 additions and 70 deletions

View File

@ -636,8 +636,8 @@ option:
archive-timeout:
section: global
type: time
default: 60
allow-range: [0.1, 86400]
default: 1m
allow-range: [100ms, 1d]
command:
archive-get: {}
archive-push: {}
@ -786,8 +786,8 @@ option:
db-timeout:
section: global
type: time
default: 1800
allow-range: [0.1, 604800]
default: 30m
allow-range: [100ms, 7d]
command:
archive-get: {}
archive-push: {}
@ -815,8 +815,8 @@ option:
io-timeout:
section: global
type: time
default: 60
allow-range: [0.1, 3600]
default: 1m
allow-range: [100ms, 1h]
command: buffer-size
job-retry:
@ -841,8 +841,8 @@ option:
job-retry-interval:
inherit: job-retry
type: time
default: 15
allow-range: [0, 900]
default: 15s
allow-range: [0s, 15m]
command:
archive-get: {}
archive-push: {}
@ -910,8 +910,8 @@ option:
protocol-timeout:
section: global
type: time
default: 1830
allow-range: [0.1, 604800]
default: 31m
allow-range: [100ms, 7d]
command:
annotate: {}
archive-get: {}

View File

@ -161,24 +161,6 @@ cvtDoubleToZ(const double value, char *const buffer, const size_t bufferSize)
FUNCTION_TEST_RETURN(SIZE, (size_t)(end - buffer + 1));
}
FN_EXTERN double
cvtZToDouble(const char *const value)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRINGZ, value);
FUNCTION_TEST_END();
ASSERT(value != NULL);
double result = 0;
sscanf(value, "%lf", &result);
if (result == 0 && strcmp(value, "0") != 0)
THROW_FMT(FormatError, "unable to convert string '%s' to double", value);
FUNCTION_TEST_RETURN(DOUBLE, result);
}
/**********************************************************************************************************************************/
FN_EXTERN size_t
cvtIntToZ(const int value, char *const buffer, const size_t bufferSize)

View File

@ -34,9 +34,8 @@ cvtCharToZ(const char value, char *const buffer, const size_t bufferSize)
return (size_t)snprintf(buffer, bufferSize, "%c", value);
}
// Convert double to zero-terminated string and vice versa
// Convert double to zero-terminated string
FN_EXTERN size_t cvtDoubleToZ(double value, char *buffer, size_t bufferSize);
FN_EXTERN double cvtZToDouble(const char *value);
// Convert int to zero-terminated string and vice versa
FN_EXTERN size_t cvtIntToZ(int value, char *buffer, size_t bufferSize);

View File

@ -3,6 +3,8 @@ Configuration Common
***********************************************************************************************************************************/
#include "build.auto.h"
#include <ctype.h>
#include "common/debug.h"
#include "common/regExp.h"
#include "common/time.h"
@ -124,5 +126,59 @@ cfgParseTime(const String *const value)
ASSERT(value != NULL);
FUNCTION_TEST_RETURN(INT64, (int64_t)(cvtZToDouble(strZ(value)) * MSEC_PER_SEC));
// Get value ptr and size
const char *const valuePtr = strZ(value);
const size_t size = strSize(value);
size_t qualifierSize = 0;
int64_t multiplier = 1000;
// Check if this is ms (the only two character qualifier)
if (size > 1 && tolower(valuePtr[size - 2]) == 'm' && tolower(valuePtr[size - 1]) == 's')
{
qualifierSize = 2;
multiplier = 1;
}
// Else check for single character qualifier
else if (size > 0)
{
switch (tolower(valuePtr[size - 1]))
{
case 's':
qualifierSize = 1;
multiplier = 1000;
break;
case 'm':
qualifierSize = 1;
multiplier = 60 * 1000;
break;
case 'h':
qualifierSize = 1;
multiplier = 60 * 60 * 1000;
break;
case 'd':
qualifierSize = 1;
multiplier = 24 * 60 * 60 * 1000;
break;
case 'w':
qualifierSize = 1;
multiplier = 7 * 24 * 60 * 60 * 1000;
break;
}
}
// Only proceed if there are numbers to parse
if (size - qualifierSize > 0)
{
// Convert string to time
const int64_t valueInt = cvtZSubNToInt64Base(valuePtr, 0, size - qualifierSize, 10);
if (valueInt <= INT64_MAX / multiplier)
FUNCTION_TEST_RETURN(INT64, valueInt * multiplier);
}
THROW_FMT(FormatError, "value '%s' is not valid", strZ(value));
}

View File

@ -17,20 +17,20 @@ static const StringPub parseRuleValueStr[] =
PARSE_RULE_STRPUB("/var/spool/pgbackrest"), // val/str
PARSE_RULE_STRPUB("1"), // val/str
PARSE_RULE_STRPUB("128MiB"), // val/str
PARSE_RULE_STRPUB("15"), // val/str
PARSE_RULE_STRPUB("1800"), // val/str
PARSE_RULE_STRPUB("1830"), // val/str
PARSE_RULE_STRPUB("15s"), // val/str
PARSE_RULE_STRPUB("1GiB"), // val/str
PARSE_RULE_STRPUB("1MiB"), // val/str
PARSE_RULE_STRPUB("1m"), // val/str
PARSE_RULE_STRPUB("2"), // val/str
PARSE_RULE_STRPUB("20MiB"), // val/str
PARSE_RULE_STRPUB("22"), // val/str
PARSE_RULE_STRPUB("256KiB"), // val/str
PARSE_RULE_STRPUB("2MiB"), // val/str
PARSE_RULE_STRPUB("3"), // val/str
PARSE_RULE_STRPUB("30m"), // val/str
PARSE_RULE_STRPUB("31m"), // val/str
PARSE_RULE_STRPUB("443"), // val/str
PARSE_RULE_STRPUB("5432"), // val/str
PARSE_RULE_STRPUB("60"), // val/str
PARSE_RULE_STRPUB("8432"), // val/str
PARSE_RULE_STRPUB("asc"), // val/str
PARSE_RULE_STRPUB("blob.core.windows.net"), // val/str
@ -70,20 +70,20 @@ typedef enum
parseRuleValStrQT_FS_var_FS_spool_FS_pgbackrest_QT, // val/str/enum
parseRuleValStrQT_1_QT, // val/str/enum
parseRuleValStrQT_128MiB_QT, // val/str/enum
parseRuleValStrQT_15_QT, // val/str/enum
parseRuleValStrQT_1800_QT, // val/str/enum
parseRuleValStrQT_1830_QT, // val/str/enum
parseRuleValStrQT_15s_QT, // val/str/enum
parseRuleValStrQT_1GiB_QT, // val/str/enum
parseRuleValStrQT_1MiB_QT, // val/str/enum
parseRuleValStrQT_1m_QT, // val/str/enum
parseRuleValStrQT_2_QT, // val/str/enum
parseRuleValStrQT_20MiB_QT, // val/str/enum
parseRuleValStrQT_22_QT, // val/str/enum
parseRuleValStrQT_256KiB_QT, // val/str/enum
parseRuleValStrQT_2MiB_QT, // val/str/enum
parseRuleValStrQT_3_QT, // val/str/enum
parseRuleValStrQT_30m_QT, // val/str/enum
parseRuleValStrQT_31m_QT, // val/str/enum
parseRuleValStrQT_443_QT, // val/str/enum
parseRuleValStrQT_5432_QT, // val/str/enum
parseRuleValStrQT_60_QT, // val/str/enum
parseRuleValStrQT_8432_QT, // val/str/enum
parseRuleValStrQT_asc_QT, // val/str/enum
parseRuleValStrQT_blob_DT_core_DT_windows_DT_net_QT, // val/str/enum
@ -277,7 +277,7 @@ static const int64_t parseRuleValueInt[] =
900000, // val/int
1048576, // val/int
1800000, // val/int
1830000, // val/int
1860000, // val/int
2097152, // val/int
3600000, // val/int
4194304, // val/int
@ -326,7 +326,7 @@ typedef enum
parseRuleValInt900000, // val/int/enum
parseRuleValInt1048576, // val/int/enum
parseRuleValInt1800000, // val/int/enum
parseRuleValInt1830000, // val/int/enum
parseRuleValInt1860000, // val/int/enum
parseRuleValInt2097152, // val/int/enum
parseRuleValInt3600000, // val/int/enum
parseRuleValInt4194304, // val/int/enum
@ -1115,7 +1115,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
PARSE_RULE_OPTIONAL_DEFAULT // opt/archive-timeout
( // opt/archive-timeout
PARSE_RULE_VAL_INT(60000), // opt/archive-timeout
PARSE_RULE_VAL_STR(QT_60_QT), // opt/archive-timeout
PARSE_RULE_VAL_STR(QT_1m_QT), // opt/archive-timeout
), // opt/archive-timeout
), // opt/archive-timeout
), // opt/archive-timeout
@ -1951,7 +1951,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
PARSE_RULE_OPTIONAL_DEFAULT // opt/db-timeout
( // opt/db-timeout
PARSE_RULE_VAL_INT(1800000), // opt/db-timeout
PARSE_RULE_VAL_STR(QT_1800_QT), // opt/db-timeout
PARSE_RULE_VAL_STR(QT_30m_QT), // opt/db-timeout
), // opt/db-timeout
), // opt/db-timeout
), // opt/db-timeout
@ -2285,7 +2285,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
PARSE_RULE_OPTIONAL_DEFAULT // opt/io-timeout
( // opt/io-timeout
PARSE_RULE_VAL_INT(60000), // opt/io-timeout
PARSE_RULE_VAL_STR(QT_60_QT), // opt/io-timeout
PARSE_RULE_VAL_STR(QT_1m_QT), // opt/io-timeout
), // opt/io-timeout
), // opt/io-timeout
), // opt/io-timeout
@ -2408,7 +2408,7 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
PARSE_RULE_OPTIONAL_DEFAULT // opt/job-retry-interval
( // opt/job-retry-interval
PARSE_RULE_VAL_INT(15000), // opt/job-retry-interval
PARSE_RULE_VAL_STR(QT_15_QT), // opt/job-retry-interval
PARSE_RULE_VAL_STR(QT_15s_QT), // opt/job-retry-interval
), // opt/job-retry-interval
), // opt/job-retry-interval
), // opt/job-retry-interval
@ -4378,8 +4378,8 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =
// opt/protocol-timeout
PARSE_RULE_OPTIONAL_DEFAULT // opt/protocol-timeout
( // opt/protocol-timeout
PARSE_RULE_VAL_INT(1830000), // opt/protocol-timeout
PARSE_RULE_VAL_STR(QT_1830_QT), // opt/protocol-timeout
PARSE_RULE_VAL_INT(1860000), // opt/protocol-timeout
PARSE_RULE_VAL_STR(QT_31m_QT), // opt/protocol-timeout
), // opt/protocol-timeout
), // opt/protocol-timeout
), // opt/protocol-timeout

View File

@ -222,7 +222,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
hrnCfgArgRawZ(argList, cfgOptPgPath, TEST_PATH "/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
HRN_CFG_LOAD(cfgCmdCheck, argList);
// -------------------------------------------------------------------------------------------------------------------------
@ -260,7 +260,7 @@ testRun(void)
hrnCfgArgKeyRawZ(argList, cfgOptPgPort, 8, "5433");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgKeyRawZ(argList, cfgOptRepoHost, 2, "repo.domain.com");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
HRN_CFG_LOAD(cfgCmdCheck, argList);
HRN_PG_CONTROL_PUT(storagePgIdxWrite(1), PG_VERSION_96);
@ -283,7 +283,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
hrnCfgArgRawZ(argList, cfgOptPgPath, TEST_PATH "/pg");
hrnCfgArgKeyRawZ(argList, cfgOptRepoHost, 1, "repo.domain.com");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
HRN_CFG_LOAD(cfgCmdCheck, argList);
HRN_PQ_SCRIPT_SET(
@ -304,7 +304,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
hrnCfgArgRawZ(argList, cfgOptPgPath, TEST_PATH "/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
hrnCfgArgRawBool(argList, cfgOptBackupStandby, true);
HRN_CFG_LOAD(cfgCmdCheck, argList);
@ -334,7 +334,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptStanza, "test1");
hrnCfgArgRawZ(argList, cfgOptPgPath, TEST_PATH "/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 8, TEST_PATH "/pg8");
hrnCfgArgKeyRawZ(argList, cfgOptPgPort, 8, "5433");
HRN_CFG_LOAD(cfgCmdCheck, argList);
@ -442,7 +442,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptConfig, TEST_PATH "/pgbackrest.conf");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo2");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
HRN_CFG_LOAD(cfgCmdCheck, argList);
// Create stanza files on repo2
@ -508,7 +508,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptPgPath, TEST_PATH "/pg");
hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH "/repo");
hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo2");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, ".5");
hrnCfgArgRawZ(argList, cfgOptArchiveTimeout, "500ms");
HRN_CFG_LOAD(cfgCmdCheck, argList);
// Create WAL segment

View File

@ -244,13 +244,13 @@ testRun(void)
" files [default=/etc/pgbackrest]\n"
" --delta restore or backup using checksums\n"
" [default=n]\n"
" --io-timeout I/O timeout [default=60]\n"
" --io-timeout I/O timeout [default=1m]\n"
" --lock-path path where lock files are stored\n"
" [default=/tmp/pgbackrest]\n"
" --neutral-umask use a neutral umask [default=y]\n"
" --process-max max processes to use for\n"
" compress/transfer [default=1]\n"
" --protocol-timeout protocol timeout [default=1830]\n"
" --protocol-timeout protocol timeout [default=31m]\n"
" --sck-keep-alive keep-alive enable [default=y]\n"
" --stanza defines the stanza\n"
" --tcp-keep-alive-count keep-alive count\n"

View File

@ -34,7 +34,7 @@ testRun(void)
}
// *****************************************************************************************************************************
if (testBegin("cvtDoubleToZ() and cvtZToDouble()"))
if (testBegin("cvtDoubleToZ()"))
{
char buffer[STACK_TRACE_PARAM_MAX];
@ -48,11 +48,6 @@ testRun(void)
TEST_RESULT_UINT(cvtDoubleToZ(999.0, buffer, STACK_TRACE_PARAM_MAX), 3, "convert double to string");
TEST_RESULT_Z(buffer, "999", " check buffer");
TEST_ERROR(cvtZToDouble("AAA"), FormatError, "unable to convert string 'AAA' to double");
TEST_RESULT_DOUBLE(cvtZToDouble("0"), 0, "convert string to double");
TEST_RESULT_DOUBLE(cvtZToDouble("123.123"), 123.123, "convert string to double");
TEST_RESULT_DOUBLE(cvtZToDouble("-999999999.123456"), -999999999.123456, "convert string to double");
}
// *****************************************************************************************************************************

View File

@ -235,11 +235,11 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptStanza, "test");
hrnCfgArgKeyRawZ(argList, cfgOptPgPath, 1, "/pg1");
hrnCfgArgRawZ(argList, cfgOptDbTimeout, "100000");
hrnCfgArgRawZ(argList, cfgOptProtocolTimeout, "50.5");
hrnCfgArgRawZ(argList, cfgOptProtocolTimeout, "50500ms");
TEST_ERROR(
hrnCfgLoadP(cfgCmdCheck, argList), OptionInvalidValueError,
"'50.5' is not valid for 'protocol-timeout' option\n"
"HINT 'protocol-timeout' option (50.5) should be greater than 'db-timeout' option (100000).");
"'50500ms' is not valid for 'protocol-timeout' option\n"
"HINT 'protocol-timeout' option (50500ms) should be greater than 'db-timeout' option (100000).");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("very small protocol-timeout triggers db-timeout special handling");
@ -823,7 +823,7 @@ testRun(void)
hrnCfgArgRawZ(argList, cfgOptLogLevelConsole, "off");
hrnCfgArgRawZ(argList, cfgOptLogLevelStderr, "off");
hrnCfgArgRawZ(argList, cfgOptLogLevelFile, "off");
hrnCfgArgRawZ(argList, cfgOptIoTimeout, "95.5");
hrnCfgArgRawZ(argList, cfgOptIoTimeout, "95500ms");
strLstAddZ(argList, CFGCMD_ARCHIVE_GET);
umask(0111);

View File

@ -593,8 +593,11 @@ testRun(void)
}
// *****************************************************************************************************************************
if (testBegin("convertToByte()"))
if (testBegin("cfgParseSize() and cfgParseTime()"))
{
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("cfgParseSize()");
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");
@ -604,6 +607,17 @@ testRun(void)
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");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("cfgParseSize()");
TEST_ERROR(cfgParseTime(STRDEF("1md")), FormatError, "unable to convert base 10 string '1m' to int64");
TEST_ERROR(cfgParseTime(STRDEF("")), FormatError, "value '' is not valid");
TEST_ERROR(cfgParseTime(STRDEF("s")), FormatError, "value 's' is not valid");
TEST_ERROR(cfgParseTime(STRDEF("999999999999w")), FormatError, "value '999999999999w' is not valid");
TEST_RESULT_INT(cfgParseTime(STRDEF("1M")), 60 * 1000, "1m");
TEST_RESULT_INT(cfgParseTime(STRDEF("2H")), 2 * 60 * 60 * 1000, "2h");
TEST_RESULT_INT(cfgParseTime(STRDEF("3W")), 3 * 7 * 24 * 60 * 60 * 1000, "3w");
}
// *****************************************************************************************************************************
@ -1372,11 +1386,11 @@ testRun(void)
strLstAddZ(argList, TEST_BACKREST_EXE);
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/db");
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
hrnCfgArgRawZ(argList, cfgOptProtocolTimeout, ".01");
hrnCfgArgRawZ(argList, cfgOptProtocolTimeout, "10ms");
strLstAddZ(argList, TEST_COMMAND_RESTORE);
TEST_ERROR(
cfgParseP(storageTest, strLstSize(argList), strLstPtr(argList), .noResetLogLevel = true), OptionInvalidValueError,
"'.01' is out of range for 'protocol-timeout' option");
"'10ms' is out of range for 'protocol-timeout' option");
argList = strLstNew();
strLstAddZ(argList, TEST_BACKREST_EXE);
@ -1869,7 +1883,7 @@ testRun(void)
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptLogLevelConsole), "warn", "log-level-console default is warn");
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptPgPort), "5432", "pg-port default is 5432");
TEST_RESULT_STR_Z(cfgOptionDisplay(cfgOptPgPort), "5432", "pg-port display is 5432");
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptDbTimeout), "1800", "db-timeout default is 1800");
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptDbTimeout), "30m", "db-timeout default is 30m");
TEST_RESULT_VOID(cfgOptionDefaultSet(cfgOptPgSocketPath, VARSTRDEF("/default")), "set pg-socket-path default");
TEST_RESULT_STR_Z(cfgOptionIdxStr(cfgOptPgSocketPath, 0), "/path/to/socket", "pg1-socket-path unchanged");