Commit e6d0a391 authored by Witold Krecicki's avatar Witold Krecicki

4223. [func] Add support for setting max-cache-size to percentage

			of available physical memory, set default to 90%.
			[RT #38442]
parent 98a7f8c7
......@@ -54,3 +54,4 @@ unit/atf-src/test-programs/cpp_helpers
unit/atf-src/test-programs/sh_helpers
# ccc-analyzer store its results in .plist directories
*.plist/
*~
4223. [func] Add support for setting max-cache-size to percentage
of available physical memory, set default to 90%.
[RT #38442]
4222. [func] Bias IPv6 servers when selecting the next server to
query. [RT #40836]
......
......@@ -368,6 +368,7 @@ do_authors_lookup(dns_sdblookup_t *lookup) {
"Bob Halley",
"Evan Hunt",
"JINMEI Tatuya",
"Witold Krecicki",
"David Lawrence",
"Scott Mann",
"Danny Mayer",
......
......@@ -160,7 +160,7 @@ options {\n\
max-ncache-ttl 10800; /* 3 hours */\n\
max-cache-ttl 604800; /* 1 week */\n\
transfer-format many-answers;\n\
max-cache-size 0;\n\
max-cache-size 90%;\n\
check-names master fail;\n\
check-names slave warn;\n\
check-names response ignore;\n\
......
......@@ -37,6 +37,7 @@
#include <isc/hmacsha.h>
#include <isc/httpd.h>
#include <isc/lex.h>
#include <isc/meminfo.h>
#include <isc/parseint.h>
#include <isc/portset.h>
#include <isc/print.h>
......@@ -131,6 +132,10 @@
#define SIZE_MAX ((size_t)-1)
#endif
#ifndef SIZE_AS_PERCENT
#define SIZE_AS_PERCENT ((size_t)-2)
#endif
#ifdef TUNE_LARGE
#define RESOLVER_NTASKS 523
#define UDPBUFFERS 32768
......@@ -2400,6 +2405,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
isc_result_t result;
unsigned int cleaning_interval;
size_t max_cache_size;
isc_uint32_t max_cache_size_percent = 0;
size_t max_acache_size;
size_t max_adb_size;
isc_uint32_t lame_ttl, fail_ttl;
......@@ -2685,6 +2691,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
str = cfg_obj_asstring(obj);
INSIST(strcasecmp(str, "unlimited") == 0);
max_cache_size = 0;
} else if (cfg_obj_ispercentage(obj)) {
max_cache_size = SIZE_AS_PERCENT;
max_cache_size_percent = cfg_obj_aspercentage(obj);
} else {
isc_resourcevalue_t value;
value = cfg_obj_asuint64(obj);
......@@ -2701,6 +2710,26 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
max_cache_size = (size_t) value;
}
if (max_cache_size == SIZE_AS_PERCENT) {
isc_uint64_t totalphys = isc_meminfo_totalphys();
max_cache_size = totalphys * max_cache_size_percent/100;
if (totalphys == 0) {
cfg_obj_log(obj, ns_g_lctx,
ISC_LOG_WARNING,
"Unable to determine amount of physical "
"memory, setting 'max-cache-size' to "
"unlimited");
} else {
cfg_obj_log(obj, ns_g_lctx,
ISC_LOG_INFO,
"'max-cache-size %d%%' "
"- setting to %luMB (out of %luMB)",
max_cache_size_percent,
max_cache_size / (1024*1024),
(unsigned long) totalphys / (1024*1024));
}
}
/* Check-names. */
obj = NULL;
result = ns_checknames_get(maps, "response", &obj);
......
......@@ -28,7 +28,7 @@ options {
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
notify yes;
max-cache-size 10000;
max-cache-size 80%;
disable-empty-zone 127.IN-ADDR.ARPA;
};
......
......@@ -261,5 +261,12 @@ grep "zone shared.example/IN: loaded serial" < checkconf.out7 > /dev/null || ret
if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
echo "I: check that named-checkconf prints max-cache-size <percentage> correctly"
ret=0
$CHECKCONF -p max-cache-size-good.conf > checkconf.out8 2>&1 || ret=1
grep "max-cache-size 60%;" checkconf.out8 > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
echo "I:exit status: $status"
exit $status
......@@ -2930,6 +2930,25 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
<varname>size_or_percent</varname>
</para>
</entry>
<entry colname="2">
<para>
<varname>size_spec</varname> or integer value
followed by '%' to represent percents.
</para>
<para>
The behaviour is exactly the same as
<varname>size_spec</varname>, but
<varname>size_or_percent</varname> allows also
to specify a positive integer value followed by
'%' sign to represent percents.
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
......@@ -4959,7 +4978,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> additional-from-auth <replaceable>yes_or_no</replaceable> ; </optional>
<optional> additional-from-cache <replaceable>yes_or_no</replaceable> ; </optional>
<optional> random-device <replaceable>path_name</replaceable> ; </optional>
<optional> max-cache-size <replaceable>size_spec</replaceable> ; </optional>
<optional> max-cache-size <replaceable>size_or_percent</replaceable> ; </optional>
<optional> match-mapped-addresses <replaceable>yes_or_no</replaceable>; </optional>
<optional> filter-aaaa-on-v4 ( <replaceable>yes_or_no</replaceable> | <replaceable>break-dnssec</replaceable> ); </optional>
<optional> filter-aaaa-on-v6 ( <replaceable>yes_or_no</replaceable> | <replaceable>break-dnssec</replaceable> ); </optional>
......@@ -8747,7 +8766,7 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
<listitem>
<para>
The maximum amount of memory to use for the
server's cache, in bytes.
server's cache, in bytes or % of total physical memory.
When the amount of data in the cache
reaches this limit, the server will cause records to
expire prematurely based on an LRU based strategy so
......@@ -8760,7 +8779,14 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
and reset to 2MB.
In a server with multiple views, the limit applies
separately to the cache of each view.
The default is <userinput>unlimited</userinput>.
The default is <userinput>90%</userinput>.
On systems where detection of amount of physical
memory is not supported values represented as %
fall back to unlimited.
Note that the detection of physical memory is done only
once at startup, so <command>named</command> will not
adjust the cache size if the amount of physical memory
is changed during runtime.
</para>
</listitem>
</varlistentry>
......
......@@ -178,12 +178,12 @@ options {
masterfile-format ( text | raw | map );
masterfile-style ( full | relative );
match-mapped-addresses <boolean>;
max-acache-size <size_no_default>;
max-cache-size <size_no_default>;
max-acache-size ( unlimited | <sizeval> );
max-cache-size ( unlimited | default | <sizeval> | <percentage> );
max-cache-ttl <integer>;
max-clients-per-query <integer>;
max-ixfr-log-size ( unlimited | default | <sizeval> ); // obsolete
max-journal-size <size_no_default>;
max-journal-size ( unlimited | <sizeval> );
max-ncache-ttl <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
......@@ -461,12 +461,12 @@ view <string> [ <class> ] {
match-clients { <address_match_element>; ... };
match-destinations { <address_match_element>; ... };
match-recursive-only <boolean>;
max-acache-size <size_no_default>;
max-cache-size <size_no_default>;
max-acache-size ( unlimited | <sizeval> );
max-cache-size ( unlimited | default | <sizeval> | <percentage> );
max-cache-ttl <integer>;
max-clients-per-query <integer>;
max-ixfr-log-size ( unlimited | default | <sizeval> ); // obsolete
max-journal-size <size_no_default>;
max-journal-size ( unlimited | <sizeval> );
max-ncache-ttl <integer>;
max-recursion-depth <integer>;
max-recursion-queries <integer>;
......@@ -645,7 +645,7 @@ view <string> [ <class> ] {
port <integer> ] ) [ key <string> ]; ... };
max-ixfr-log-size ( unlimited | default |
<sizeval> ); // obsolete
max-journal-size <size_no_default>;
max-journal-size ( unlimited | <sizeval> );
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
......@@ -746,7 +746,7 @@ zone <string> [ <class> ] {
<ipv4_address> [ port <integer> ] | <ipv6_address> [ port
<integer> ] ) [ key <string> ]; ... };
max-ixfr-log-size ( unlimited | default | <sizeval> ); // obsolete
max-journal-size <size_no_default>;
max-journal-size ( unlimited | <sizeval> );
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
......
......@@ -37,9 +37,10 @@ CWARNINGS =
UNIXOBJS = @ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \
unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \
unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \
unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \
unix/os.@O@ unix/resource.@O@ unix/socket.@O@ unix/stdio.@O@ \
unix/stdtime.@O@ unix/strerror.@O@ unix/syslog.@O@ unix/time.@O@
unix/interfaceiter.@O@ unix/keyboard.@O@ unix/meminfo.@O@ \
unix/net.@O@ unix/os.@O@ unix/resource.@O@ unix/socket.@O@ \
unix/stdio.@O@ unix/stdtime.@O@ unix/strerror.@O@ \
unix/syslog.@O@ unix/time.@O@
NLSOBJS = nls/msgcat.@O@
......@@ -48,8 +49,8 @@ THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@
THREADOBJS = @THREADOPTOBJS@ @ISC_THREAD_DIR@/thread.@O@
WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
win32/fsaccess.@O@ win32/once.@O@ win32/stdtime.@O@ \
win32/thread.@O@ win32/time.@O@
win32/fsaccess.@O@ win32/meminfo.@O@ win32/once.@O@ \
win32/stdtime.@O@ win32/thread.@O@ win32/time.@O@
# Alphabetically
OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \
......
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ISC_MEMINFO_H
#define ISC_MEMINFO_H 1
#include <isc/types.h>
#include <isc/lang.h>
ISC_LANG_BEGINDECLS
isc_uint64_t
isc_meminfo_totalphys(void);
/*%<
* Return total available physical memory in bytes, or 0 if this cannot
* be determined
*/
ISC_LANG_ENDDECLS
#endif /* ISC_MEMINFO_H */
......@@ -31,15 +31,15 @@ CWARNINGS =
# Alphabetically
OBJS = @ISC_IPV6_O@ @ISC_PK11_API_O@ \
app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \
fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \
os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \
fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ meminfo.@O@ \
net.@O@ os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \
strerror.@O@ syslog.@O@ time.@O@
# Alphabetically
SRCS = @ISC_IPV6_C@ @ISC_PK11_API_C@ \
app.c dir.c entropy.c errno2result.c file.c \
fsaccess.c interfaceiter.c keyboard.c net.c \
os.c resource.c socket.c stdio.c stdtime.c \
fsaccess.c interfaceiter.c keyboard.c meminfo.c \
net.c os.c resource.c socket.c stdio.c stdtime.c \
strerror.c syslog.c time.c
SUBDIRS = include
......
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <isc/meminfo.h>
#include <unistd.h>
#include <sys/sysctl.h>
isc_uint64_t
isc_meminfo_totalphys(void) {
#if defined(CTL_HW) && (defined(HW_PHYSMEM64) || defined(HW_MEMSIZE))
int mib[2];
mib[0] = CTL_HW;
#if defined(HW_MEMSIZE)
mib[1] = HW_MEMSIZE;
#elif defined(HW_PHYSMEM64)
mib[1] = HW_PHYSMEM64;
#endif
isc_uint64_t size = 0;
size_t len = sizeof(size);
if (sysctl(mib, 2, &size, &len, NULL, 0) == 0)
return (size);
#endif
#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
return ((size_t) (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)));
#endif
return (0);
}
......@@ -27,11 +27,11 @@ CDEFINES =
CWARNINGS =
# Alphabetically
OBJS = condition.@O@ dir.@O@ file.@O@ fsaccess.@O@ once.@O@ \
stdtime.@O@ thread.@O@ time.@O@ @ISC_PK11_API_O@
OBJS = condition.@O@ dir.@O@ file.@O@ meminfo.@O@ fsaccess.@O@ \
once.@O@ stdtime.@O@ thread.@O@ time.@O@ @ISC_PK11_API_O@
# Alphabetically
SRCS = condition.c dir.c file.c once.c fsaccess.c \
SRCS = condition.c dir.c file.c meminfo.c once.c fsaccess.c \
stdtime.c thread.c time.c @ISC_PK11_API_C@
SUBDIRS = include
......
/*
* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <windows.h>
#include <isc/meminfo.h>
isc_uint64_t
isc_meminfo_totalphys(void) {
MEMORYSTATUSEX statex;
status.dwLength = sizeof(statex);
GlobalMemoryStatusEx(&statex);
return ((size_t)statex.ullTotalPhys);
}
\ No newline at end of file
......@@ -190,6 +190,18 @@ cfg_obj_ismap(const cfg_obj_t *obj);
* Return true iff 'obj' is of a map type.
*/
isc_boolean_t
cfg_obj_isfixedpoint(const cfg_obj_t *obj);
/*%<
* Return true iff 'obj' is of a fixedpoint type.
*/
isc_boolean_t
cfg_obj_ispercentage(const cfg_obj_t *obj);
/*%<
* Return true iff 'obj' is of a percentage type.
*/
isc_result_t
cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj);
/*%<
......@@ -297,6 +309,18 @@ cfg_obj_asfixedpoint(const cfg_obj_t *obj);
* \li A 32-bit unsigned integer.
*/
isc_uint32_t
cfg_obj_aspercentage(const cfg_obj_t *obj);
/*%<
* Returns the value of a configuration object of percentage
*
* Requires:
* \li 'obj' points to a valid configuration object of percentage type.
*
* Returns:
* \li A 32-bit unsigned integer.
*/
isc_boolean_t
cfg_obj_isstring(const cfg_obj_t *obj);
/*%<
......
......@@ -267,6 +267,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint;
LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage;
/*@}*/
/*@{*/
......@@ -292,6 +293,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_void;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_fixedpoint;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_percentage;
/*@}*/
isc_result_t
......@@ -455,11 +457,19 @@ void
cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type);
isc_result_t
cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret);
void
cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj);
isc_result_t
cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret);
void
cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj);
isc_result_t
cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
......
......@@ -133,6 +133,7 @@ static cfg_type_t cfg_type_server;
static cfg_type_t cfg_type_server_key_kludge;
static cfg_type_t cfg_type_size;
static cfg_type_t cfg_type_sizenodefault;
static cfg_type_t cfg_type_sizeorpercent;
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
static cfg_type_t cfg_type_statschannels;
......@@ -1595,7 +1596,7 @@ view_clauses[] = {
{ "nocookie-udp-size", &cfg_type_uint32, 0 },
{ "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
{ "max-acache-size", &cfg_type_sizenodefault, 0 },
{ "max-cache-size", &cfg_type_sizenodefault, 0 },
{ "max-cache-size", &cfg_type_sizeorpercent, 0 },
{ "max-cache-ttl", &cfg_type_uint32, 0 },
{ "max-clients-per-query", &cfg_type_uint32, 0 },
{ "max-ncache-ttl", &cfg_type_uint32, 0 },
......@@ -2065,6 +2066,56 @@ parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (result);
}
static isc_result_t
parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
char *endp;
isc_result_t result;
cfg_obj_t *obj = NULL;
isc_uint64_t val;
isc_uint32_t percent;
UNUSED(type);
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
result = ISC_R_UNEXPECTEDTOKEN;
goto cleanup;
}
percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10);
if (*endp == '%' && *(endp+1) == 0) {
CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
obj->value.uint32 = percent;
*ret = obj;
return (ISC_R_SUCCESS);
} else {
CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
obj->value.uint64 = val;
*ret = obj;
return (ISC_R_SUCCESS);
}
cleanup:
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit or percent");
return (result);
}
static void
doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
UNUSED(type);
cfg_print_cstr(pctx, "( ");
cfg_doc_terminal(pctx, &cfg_type_size);
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_percentage);
cfg_print_cstr(pctx, " )");
}
/*%
* A size value (number + optional unit).
*/
......@@ -2097,10 +2148,42 @@ static cfg_type_t cfg_type_size = {
*/
static const char *sizenodefault_enums[] = { "unlimited", NULL };
static cfg_type_t cfg_type_sizenodefault = {
"size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
"size_no_default", parse_size, cfg_print_ustring, doc_size,
&cfg_rep_string, sizenodefault_enums
};
/*%
* A size in absolute values or percents.
*/
static cfg_type_t cfg_type_sizeval_percent = {
"sizeval_percent", parse_sizeval_percent, cfg_print_ustring,
doc_sizeval_percent, &cfg_rep_string, NULL
};
/*%
* A size in absolute values or percents, or "unlimited", or "default"
*/
static isc_result_t
parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent,
ret));
}
static void
doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_sizeval_percent);
}
static const char *sizeorpercent_enums[] = { "unlimited", "default", NULL };
static cfg_type_t cfg_type_sizeorpercent = {
"size_or_percent", parse_size_or_percent, cfg_print_ustring,
doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums
};
/*%
* optional_keyvalue
*/
......@@ -2170,7 +2253,13 @@ doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
first = ISC_FALSE;
cfg_print_cstr(pctx, *p);
}
if (othertype != &cfg_type_void) {
if (othertype == &cfg_type_sizeval_percent) {
if (!first)
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_sizeval);
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_percentage);
} else if (othertype != &cfg_type_void) {
if (!first)
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, othertype);
......
......@@ -123,6 +123,7 @@ cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
cfg_rep_t cfg_rep_void = { "void", free_noop };
cfg_rep_t cfg_rep_fixedpoint = { "fixedpoint", free_noop };
cfg_rep_t cfg_rep_percentage = { "percentage", free_noop };
/*
* Configuration type definitions.
......@@ -650,6 +651,69 @@ cfg_type_t cfg_type_void = {
"void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
NULL };
/*
* percentage
*/
isc_result_t
cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
char *endp;
isc_result_t result;
cfg_obj_t *obj = NULL;
isc_uint32_t percent;
UNUSED(type);
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string) {
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected percentage");
return (ISC_R_UNEXPECTEDTOKEN);
}
percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10);
if (*endp != '%' || *(endp+1) != 0) {
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected percentage");
return (ISC_R_UNEXPECTEDTOKEN);
}
CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
obj->value.uint32 = percent;
*ret = obj;
cleanup:
return (result);
}
void
cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) {
char buf[64];
int n;
n = snprintf(buf, sizeof(buf), "%u%%", obj->value.uint32);
INSIST(n > 0 && (size_t)n < sizeof(buf));