Skip to content

Commit 78f4726

Browse files
committed
mem: HG_MALLOC - slab allocator with elastic arenas
A new shared- and private-memory allocator, selected at runtime with -a HG_MALLOC (or -s/-k for one memory type); no behaviour change for existing configurations. - 21 size classes (64 B - 64 KB) served from per-process free lists, so the common allocation and free take no lock; cells move between processes through a shared per-class pool, in batches. Larger requests go to a coalescing large tier. - A transfer cache in each shared arena parks a donated private chain whole and hands it whole to a refill, a pointer swap under the arena lock instead of a per-cell walk; up to 64 chains per class, 1/128 of the arena and at most 32 MB. An idle class gives one chain back to its blocks per GC cycle; a carve at exhaustion drains them all. - Blocks are carved from a buddy allocator over a grid of pages the size of the host's huge page (2 MB on x86-64; 256 KB for small arenas on 4 KB memory), whichever tier backs them; a block whose cells are all free returns to the buddy and can be re-cut for any class. - The arena is acquired through a four-tier ladder - MAP_HUGETLB, THP via MADV_HUGEPAGE, MADV_COLLAPSE, plain 4 KB pages - each tier verified from the kernel's counters. Huge pages are an optimisation, not a requirement. MAP_HUGETLB is for shared arenas only; a private arena starts on THP or 4 KB pages. A refused MAP_HUGETLB is logged with the pool's free pages per NUMA node. On tier 3 a grow done by a worker that ran out of memory is published on 4 KB pages at once and the maintenance process collapses it afterwards, so no worker waits for MADV_COLLAPSE. - Elastic arenas: -m INIT:CAP / -M INIT:CAP (k/m/g suffixes, bare numbers in MB) reserve the cap and commit pages on demand, in a configurable granule (shm_grow_granule / pkg_grow_granule), growing on exhaustion or ahead of it through an auto_scaling_profile (shm_/pkg_auto_scaling_profile), and releasing quiet pages. A maintenance process grows ahead of demand and runs the release with the arena lock dropped. Growth stops at the cap, the backing tier and a host free-memory floor (hg_ram_floor_mb); a sustained refusal by the backing or the floor latches GROW-BLOCKED, raised as E_CORE_SHM_GROW_BLOCKED (reaching the cap is only a notice). - Host memory is checked before anything is committed, on every tier (MemAvailable above hg_ram_floor_mb, the memory cgroup's limit, plus the hugetlb pool for arenas on hugetlb pages): at startup for every process's -M INIT (refuse when the startup processes do not fit, warn for the auto-scaling maximum and for caps beyond MemTotal), before each fork (an auto-scaler fork that does not fit is skipped), and on each arena creation and grow. - On hugetlb pages every grow is an mlock() of the new range, and mlock() checks RLIMIT_MEMLOCK there as well: the arena warns at startup (and under -C) when the limit cannot cover its growth, and a refused grow names the resource that ran out - the limit or the hugetlb pool. On 4 KB and THP pages a limit too low to pin the arena leaves it running and growing unpinned (swappable) instead. - Every cell header carries the cell's state and a check over its address, class and state; a free moves it from live to free in one compare-and-swap, so a double free is refused, also from two processes at once, and a damaged header is refused, not followed. A per-block free map at the pool boundary stops a free-list walk at a scribbled link. Each is counted and logged and the process keeps running. hg_mem_check = 1 adds a tail guard checked at free and realloc, 2 also aborts on the first corruption. HG_MALLOC_DBG adds red zones and a quarantine of freed cells. ASan or Valgrind (-DHG_VALGRIND) is told which bytes of a private arena a caller may touch, ThreadSanitizer about the arena lock. - core:hg_stats (MI) per arena: tier, committed/reserved, per-class carve and reuse, grows/shrinks, the last grow refusal and its cause, whether the arena runs unpinned, transfer-cache puts/gets and parked chains, failed allocations (alloc_failed, out_of_memory), lock hold/wait histograms per reason and the corruption counters; core:hg_advise (MI) recommends -m/-M from the peaks reached; an hgmem: statistics group, including hg_pkg_grow_refused and hg_pkg_grow_blocked summed over every process's private arena; E_CORE_HG_LOCK_STALL for a hold above hg_lock_stall_us. - mem/mem_arena.h: a module may ask for its own HG-managed arena, independent of the core allocator choice (stubs returning NULL when HG is not built). - Unit tests (mem/test) for the allocator and its pkg/shm integration, fork, double free, corruption and growth cases; CI runs the unit tests with HG_MALLOC and HG_MALLOC_DBG as well. - modules/hgstress: a soak and fault-injection test module, excluded from the default build. Every worker churns stamped shm cells across all classes and the large tier and verifies the stamps while the others churn; MI commands park and release memory to drive grow and shrink, and inject a double free, an overrun or a scribbled free-list link. - Three fixes to existing code: the default allocator Q_MALLOC_DBG left a build without DBG_MALLOC unable to start unless -a was given (it is Q_MALLOC there now); an "#elif define F_PARALEL_MALLOC" typo in shm_mem.c; and add_stats_group() sized a group's array as sizeof(stat_var) * no + 1, giving the first stat a 1-byte array. Design, configuration, deployment and test procedures: mem/README.hg_malloc.md.
1 parent 7a4e46b commit 78f4726

75 files changed

Lines changed: 14469 additions & 47 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/unittests.yml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,35 @@ jobs:
147147
MAKE_TGT: 'test'
148148
run: script -e unit_tests.log -c 'sh -x scripts/build/do_build.sh DEFS_EXTRA_OPTS="-DUNIT_TESTS -fPIE -fPIC"'
149149

150+
# the same tests and the allocator suites with HG_MALLOC; the grep fails
151+
# the step if HG_MALLOC was not actually the allocator under test (not
152+
# anchored: other processes' log lines can share a line with the TAP one)
153+
- name: Run tests with HG_MALLOC
154+
env:
155+
MAKE_TGT: 'test'
156+
UT_ALLOC: 'HG_MALLOC'
157+
UT_MEM: '-m 64:1024 -M 16:256'
158+
run: |
159+
script -e unit_tests_hg.log -c 'sh -x scripts/build/do_build.sh DEFS_EXTRA_OPTS="-DUNIT_TESTS -fPIE -fPIC"'
160+
grep -E 'ok [0-9]+ - HG_MALLOC serves pkg and shm' unit_tests_hg.log | grep -q -v 'not ok'
161+
162+
- name: Run tests with HG_MALLOC_DBG
163+
env:
164+
MAKE_TGT: 'test'
165+
UT_ALLOC: 'HG_MALLOC_DBG'
166+
UT_MEM: '-m 64:1024 -M 16:256'
167+
run: |
168+
script -e unit_tests_hg_dbg.log -c 'sh -x scripts/build/do_build.sh DEFS_EXTRA_OPTS="-DUNIT_TESTS -fPIE -fPIC"'
169+
grep -E 'ok [0-9]+ - HG_MALLOC serves pkg and shm' unit_tests_hg_dbg.log | grep -q -v 'not ok'
170+
150171
- name: Collect test logs
151172
uses: actions/upload-artifact@v7
152173
with:
153174
name: unit_tests-logs_${{ matrix.os }}_${{ matrix.compiler }}
154175
path: |
155176
unit_tests.log
177+
unit_tests_hg.log
178+
unit_tests_hg_dbg.log
156179
157180
all_done:
158181
needs: build_and_test

‎Makefile.conf.template‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
#uuid= UUID generator | uuid-dev
7777

7878
# Modules omitted from the default build, generally due to external dependencies.
79-
exclude_modules?= aaa_diameter aaa_radius auth_jwt auth_web3 b2b_logic_xml cachedb_cassandra cachedb_couchbase cachedb_dynamodb cachedb_memcached cachedb_mongodb cachedb_redis carrierroute cgrates compression cpl_c db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_sqlite db_unixodbc dialplan emergency event_rabbitmq event_kafka event_sqs h350 httpd http2d identity jabber json launch_darkly ldap lua mi_xmlrpc mmgeoip opentelemetry osp perl pi_http presence presence_dialoginfo presence_mwi presence_reginfo presence_xml presence_dfks proto_ipsec proto_sctp proto_tls proto_wss pua pua_bla pua_dialoginfo pua_mi pua_reginfo pua_usrloc pua_xmpp python regex rabbitmq_consumer rest_client rls rtp.io siprec sngtc snmpstats stir_shaken tls_mgm tls_openssl tls_wolfssl uuid xcap xcap_client xml xmpp
79+
exclude_modules?= aaa_diameter aaa_radius auth_jwt auth_web3 b2b_logic_xml cachedb_cassandra cachedb_couchbase cachedb_dynamodb cachedb_memcached cachedb_mongodb cachedb_redis carrierroute cgrates compression cpl_c db_berkeley db_http db_mysql db_oracle db_perlvdb db_postgres db_sqlite db_unixodbc dialplan emergency event_rabbitmq event_kafka event_sqs h350 hgstress httpd http2d identity jabber json launch_darkly ldap lua mi_xmlrpc mmgeoip opentelemetry osp perl pi_http presence presence_dialoginfo presence_mwi presence_reginfo presence_xml presence_dfks proto_ipsec proto_sctp proto_tls proto_wss pua pua_bla pua_dialoginfo pua_mi pua_reginfo pua_usrloc pua_xmpp python regex rabbitmq_consumer rest_client rls rtp.io siprec sngtc snmpstats stir_shaken tls_mgm tls_openssl tls_wolfssl uuid xcap xcap_client xml xmpp
8080

8181
# Modules forced into the build, even when also listed in exclude_modules.
8282
include_modules?=
@@ -101,6 +101,12 @@ DEFS+= -DQ_MALLOC #Quality assurance memory allocator with runtime safety checks
101101
DEFS+= -DHP_MALLOC #High performance allocator with fine-grained locking
102102
DEFS+= -DDBG_MALLOC #Include additional, debug-enabled allocator flavors
103103
DEFS+= -DF_PARALLEL_MALLOC #Fast memory allocator with paralel buckets
104+
DEFS+= -DHG_MALLOC #Slab allocator with a lock-free fast path and elastic arenas
105+
# HG_MALLOC: select with -a HG_MALLOC. -m/-M accept INIT:CAP, e.g. -m 128:1024:
106+
# start at 128 MB, grow on demand up to 1 GB, give memory back when idle.
107+
# Uses huge pages when the host has them (hugetlb pool or THP), else 4 KB
108+
# pages. The committed arena is mlock()ed: run with LimitMEMLOCK=infinity.
109+
# See mem/README.hg_malloc.md
104110
#DEFS+= -DQM_DBG_MALLOC_HIST=3 #Size of debug history for Q_MALLOC (default is 1)
105111
#DEFS+= -DNO_DEBUG #Compile out all debug messages
106112
#DEFS+= -DNO_LOG #Compile out all logging

‎Makefile.defs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ MKTAGS=ctags -R .
564564
# decently fast allocator with extra sanity checks + safety buffers
565565
# -DHP_MALLOC
566566
# high performance allocator optimized for shared memory multiprocessing
567+
# -DHG_MALLOC
568+
# slab allocator with a lock-free fast path and elastic arenas
569+
# (-m INIT:CAP), on huge pages when the host provides them
567570
# -DDBG_MALLOC
568571
# will cause each of the enabled allocators to also include a "debugging"
569572
# flavor of itself; by running a debugging version of an allocator, you

‎Makefile.test‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ endif
66

77
.PHONY: test unit_tests system_tests
88

9+
# allocator and memory sizes the unit tests run with, e.g.
10+
# make test UT_ALLOC=HG_MALLOC UT_MEM="-m 64:1024 -M 16:256"
11+
UT_ALLOC ?= HP_MALLOC
12+
UT_MEM ?=
13+
914
ifneq (,$(findstring UNIT_TESTS,$(DEFS)))
1015
include Makefile.openssl
1116
misclibs=lib/digest_auth/libdigest_auth.a
@@ -24,7 +29,7 @@ endif
2429

2530
unit_tests: ensure_test_defs $(NAME)
2631
-@echo " ============= Start Unit Tests ============="
27-
./$(NAME) -dd -T $(module) -w . -a HP_MALLOC
32+
./$(NAME) -dd -T $(module) -w . -a $(UT_ALLOC) $(UT_MEM)
2833
-@echo " ================================================"
2934
-@echo " ======== Passed All Tests! ᕦ(ò_óˇ)ᕤ ========"
3035
-@echo " ================================================"

‎cfg.lex‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,18 @@ DB_DEFAULT_URL "db_default_url"
294294
DB_MAX_ASYNC_CONNECTIONS "db_max_async_connections"
295295
DISABLE_503_TRANSLATION "disable_503_translation"
296296
AUTO_SCALING_PROFILE "auto_scaling_profile"
297+
SHM_AUTO_SCALING_PROFILE "shm_auto_scaling_profile"
298+
PKG_AUTO_SCALING_PROFILE "pkg_auto_scaling_profile"
299+
HG_RAM_FLOOR_MB "hg_ram_floor_mb"
300+
HG_AUTOSCALE_DRY_RUN "hg_autoscale_dry_run"
301+
SHM_GROW_GRANULE "shm_grow_granule"
302+
PKG_GROW_GRANULE "pkg_grow_granule"
303+
HG_LOCK_STALL_US "hg_lock_stall_us"
304+
HG_GROW_AHEAD "hg_grow_ahead"
305+
HG_INTERIOR_RELEASE "hg_interior_release"
306+
HG_SCALING_CYCLE "hg_scaling_cycle"
307+
HG_SHRINK_STEP "hg_shrink_step"
308+
HG_MEM_CHECK "hg_mem_check"
297309
AUTO_SCALING_CYCLE "auto_scaling_cycle"
298310
TIMER_WORKERS "timer_workers"
299311

@@ -553,6 +565,30 @@ SPACE [ ]
553565
return DISABLE_503_TRANSLATION; }
554566
<INITIAL>{AUTO_SCALING_PROFILE} { count(); yylval.strval=yytext;
555567
return AUTO_SCALING_PROFILE; }
568+
<INITIAL>{SHM_AUTO_SCALING_PROFILE} { count(); yylval.strval=yytext;
569+
return SHM_AUTO_SCALING_PROFILE; }
570+
<INITIAL>{PKG_AUTO_SCALING_PROFILE} { count(); yylval.strval=yytext;
571+
return PKG_AUTO_SCALING_PROFILE; }
572+
<INITIAL>{HG_RAM_FLOOR_MB} { count(); yylval.strval=yytext;
573+
return HG_RAM_FLOOR_MB; }
574+
<INITIAL>{HG_AUTOSCALE_DRY_RUN} { count(); yylval.strval=yytext;
575+
return HG_AUTOSCALE_DRY_RUN; }
576+
<INITIAL>{SHM_GROW_GRANULE} { count(); yylval.strval=yytext;
577+
return SHM_GROW_GRANULE; }
578+
<INITIAL>{PKG_GROW_GRANULE} { count(); yylval.strval=yytext;
579+
return PKG_GROW_GRANULE; }
580+
<INITIAL>{HG_LOCK_STALL_US} { count(); yylval.strval=yytext;
581+
return HG_LOCK_STALL_US; }
582+
<INITIAL>{HG_GROW_AHEAD} { count(); yylval.strval=yytext;
583+
return HG_GROW_AHEAD; }
584+
<INITIAL>{HG_INTERIOR_RELEASE} { count(); yylval.strval=yytext;
585+
return HG_INTERIOR_RELEASE; }
586+
<INITIAL>{HG_SCALING_CYCLE} { count(); yylval.strval=yytext;
587+
return HG_SCALING_CYCLE; }
588+
<INITIAL>{HG_SHRINK_STEP} { count(); yylval.strval=yytext;
589+
return HG_SHRINK_STEP; }
590+
<INITIAL>{HG_MEM_CHECK} { count(); yylval.strval=yytext;
591+
return HG_MEM_CHECK; }
556592
<INITIAL>{AUTO_SCALING_CYCLE} { count(); yylval.strval=yytext;
557593
return AUTO_SCALING_CYCLE; }
558594
<INITIAL>{TIMER_WORKERS} { count(); yylval.strval=yytext;

‎cfg.y‎

Lines changed: 161 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
#include "name_alias.h"
102102
#include "ut.h"
103103
#include "pt_scaling.h"
104+
#include <limits.h>
104105
#include "dset.h"
105106
#include "pvar.h"
106107
#include "blacklists.h"
@@ -197,6 +198,56 @@ union route_name_var {
197198
void *data;
198199
} rn_tmp;
199200

201+
/* A profile size number with an optional k/m/g suffix. A suffix-less
202+
* number passes through POSITIVE, keeping the profile's legacy unit
203+
* (process count for the worker scaler, MB for the memory arenas); a
204+
* suffixed number is normalized to KB and carried NEGATED, so the two
205+
* kinds survive yacc's plain-int value stack without a union member the
206+
* lexer's cfg.tab.h could not see the type of. scale_suffix_kb() encodes,
207+
* create_scaling_profile_units() decodes. */
208+
static long scale_suffix_kb(long num, const char *suf)
209+
{
210+
if (!suf || !suf[0] || suf[1] || num <= 0)
211+
return 0;
212+
switch (suf[0]) {
213+
case 'k': case 'K': return -num;
214+
case 'm': case 'M':
215+
return num > LONG_MAX / 1024 ? 0 : -(num * 1024);
216+
case 'g': case 'G':
217+
return num > LONG_MAX / (1024 * 1024) ? 0 :
218+
-(num * 1024 * 1024);
219+
}
220+
return 0;
221+
}
222+
223+
/* wraps create_auto_scaling_profile(): when either size carries a suffix
224+
* (arrives negated, in KB), normalize BOTH to KB (a bare number is then
225+
* read as MB) and flag the profile, so hg_autoscale_apply() knows the
226+
* unit. Suffix-less profiles take the untouched legacy path - the worker
227+
* scaler never sees a change. */
228+
static int create_scaling_profile_units(char *name,
229+
long up, int u_pct, int u_need, int u_win,
230+
long down, int d_pct, int d_cyc, int d_delay)
231+
{
232+
struct scaling_profile *p;
233+
int kb = up < 0 || down < 0;
234+
235+
if (kb) {
236+
up = up < 0 ? -up : up * 1024;
237+
down = down < 0 ? -down : down * 1024;
238+
}
239+
if (create_auto_scaling_profile(name, up, u_pct, u_need, u_win,
240+
down, d_pct, d_cyc, d_delay) < 0)
241+
return -1;
242+
if (kb) {
243+
p = get_scaling_profile(name);
244+
if (!p)
245+
return -1;
246+
p->mem_kb_units = 1;
247+
}
248+
return 0;
249+
}
250+
200251
#ifndef SHM_EXTRA_STATS
201252
struct multi_str{
202253
char *s;
@@ -411,6 +462,18 @@ extern int cfg_parse_only_routes;
411462
%token ASYNC_TOKEN
412463
%token LAUNCH_TOKEN
413464
%token AUTO_SCALING_PROFILE
465+
%token SHM_AUTO_SCALING_PROFILE
466+
%token PKG_AUTO_SCALING_PROFILE
467+
%token HG_RAM_FLOOR_MB
468+
%token HG_AUTOSCALE_DRY_RUN
469+
%token SHM_GROW_GRANULE
470+
%token PKG_GROW_GRANULE
471+
%token HG_LOCK_STALL_US
472+
%token HG_GROW_AHEAD
473+
%token HG_INTERIOR_RELEASE
474+
%token HG_SCALING_CYCLE
475+
%token HG_SHRINK_STEP
476+
%token HG_MEM_CHECK
414477
%token AUTO_SCALING_CYCLE
415478
%token TIMER_WORKERS
416479

@@ -508,6 +571,7 @@ extern int cfg_parse_only_routes;
508571
%type <sockid> listen_id_def
509572
%type <sockid> phostport phostportrange
510573
%type <bondlst> socket_bond_elems
574+
%type <intval> scale_size
511575
%type <intval> proto port any_proto
512576
%type <strval> host_sep
513577
%type <intval> equalop compop matchop strop intop
@@ -928,32 +992,40 @@ mpath_def_list: mpath_def_list COLON STRING {IFOR(); add_mpath($3);}
928992
| STRING { IFOR(); add_mpath($1);}
929993
;
930994

995+
scale_size: NUMBER { $$ = $1; }
996+
| NUMBER ID {
997+
$$ = scale_suffix_kb($1, $2);
998+
if ($$ == 0)
999+
yyerror("bad size suffix - use k, m or g");
1000+
}
1001+
;
1002+
9311003
auto_scale_profile_def:
932-
ID SCALE_UP_TO NUMBER ON NUMBER MODULO FOR
1004+
ID SCALE_UP_TO scale_size ON NUMBER MODULO FOR
9331005
NUMBER CYCLES_WITHIN NUMBER
934-
SCALE_DOWN_TO NUMBER ON NUMBER MODULO FOR
1006+
SCALE_DOWN_TO scale_size ON NUMBER MODULO FOR
9351007
NUMBER CYCLES { IFOR();
936-
if (create_auto_scaling_profile($1,$3,$5,$8,$10,
1008+
if (create_scaling_profile_units($1,$3,$5,$8,$10,
9371009
$12, $14, $17,10*$17)<0)
9381010
yyerror("failed to create auto scaling profile");
9391011
}
940-
| ID SCALE_UP_TO NUMBER ON NUMBER MODULO FOR
1012+
| ID SCALE_UP_TO scale_size ON NUMBER MODULO FOR
9411013
NUMBER CYCLES
942-
SCALE_DOWN_TO NUMBER ON NUMBER MODULO FOR
1014+
SCALE_DOWN_TO scale_size ON NUMBER MODULO FOR
9431015
NUMBER CYCLES { IFOR();
944-
if (create_auto_scaling_profile($1,$3,$5,$8,$8,
1016+
if (create_scaling_profile_units($1,$3,$5,$8,$8,
9451017
$11, $13, $16, 10*$16)<0)
9461018
yyerror("failed to create auto scaling profile");
9471019
}
948-
| ID SCALE_UP_TO NUMBER ON NUMBER MODULO FOR
1020+
| ID SCALE_UP_TO scale_size ON NUMBER MODULO FOR
9491021
NUMBER CYCLES_WITHIN NUMBER { IFOR();
950-
if (create_auto_scaling_profile($1,$3,$5,$8,$10,
1022+
if (create_scaling_profile_units($1,$3,$5,$8,$10,
9511023
0, 0, 0, 0)<0)
9521024
yyerror("failed to create auto scaling profile");
9531025
}
954-
| ID SCALE_UP_TO NUMBER ON NUMBER MODULO FOR
1026+
| ID SCALE_UP_TO scale_size ON NUMBER MODULO FOR
9551027
NUMBER CYCLES { IFOR();
956-
if (create_auto_scaling_profile($1,$3,$5,$8,$8,
1028+
if (create_scaling_profile_units($1,$3,$5,$8,$8,
9571029
0, 0, 0, 0)<0)
9581030
yyerror("failed to create auto scaling profile");
9591031
}
@@ -1673,6 +1745,85 @@ assign_stm: LOGLEVEL EQUAL snumber { IFOR();
16731745
| AUTO_SCALING_PROFILE EQUAL error {
16741746
yyerror("bad auto-scaling profile definition");
16751747
}
1748+
| SHM_AUTO_SCALING_PROFILE EQUAL ID { IFOR();
1749+
hg_shm_profile_name=$3; }
1750+
| SHM_AUTO_SCALING_PROFILE EQUAL error {
1751+
yyerror("profile name expected");
1752+
}
1753+
| PKG_AUTO_SCALING_PROFILE EQUAL ID { IFOR();
1754+
hg_pkg_profile_name=$3; }
1755+
| PKG_AUTO_SCALING_PROFILE EQUAL error {
1756+
yyerror("profile name expected");
1757+
}
1758+
| HG_RAM_FLOOR_MB EQUAL NUMBER { IFOR();
1759+
hg_ram_floor_mb=$3; }
1760+
| HG_RAM_FLOOR_MB EQUAL error {
1761+
yyerror("integer value expected");
1762+
}
1763+
| HG_AUTOSCALE_DRY_RUN EQUAL NUMBER { IFOR();
1764+
hg_autoscale_dry_run=$3; }
1765+
| HG_AUTOSCALE_DRY_RUN EQUAL error {
1766+
yyerror("integer value expected");
1767+
}
1768+
| SHM_GROW_GRANULE EQUAL scale_size { IFOR();
1769+
/* scale_size: positive = MB, negated = KB */
1770+
hg_shm_grow_granule = $3 < 0 ?
1771+
(unsigned long)(-$3) << 10 :
1772+
(unsigned long)$3 << 20;
1773+
}
1774+
| SHM_GROW_GRANULE EQUAL error {
1775+
yyerror("size expected (number, optional k/m/g)");
1776+
}
1777+
| PKG_GROW_GRANULE EQUAL scale_size { IFOR();
1778+
hg_pkg_grow_granule = $3 < 0 ?
1779+
(unsigned long)(-$3) << 10 :
1780+
(unsigned long)$3 << 20;
1781+
}
1782+
| PKG_GROW_GRANULE EQUAL error {
1783+
yyerror("size expected (number, optional k/m/g)");
1784+
}
1785+
| HG_LOCK_STALL_US EQUAL NUMBER { IFOR();
1786+
hg_lock_stall_us=$3; }
1787+
| HG_LOCK_STALL_US EQUAL error {
1788+
yyerror("integer value expected");
1789+
}
1790+
| HG_GROW_AHEAD EQUAL NUMBER { IFOR();
1791+
hg_grow_ahead=$3; }
1792+
| HG_GROW_AHEAD EQUAL error {
1793+
yyerror("integer value expected");
1794+
}
1795+
| HG_INTERIOR_RELEASE EQUAL NUMBER { IFOR();
1796+
hg_interior_release=$3; }
1797+
| HG_INTERIOR_RELEASE EQUAL error {
1798+
yyerror("integer value expected");
1799+
}
1800+
| HG_SCALING_CYCLE EQUAL NUMBER { IFOR();
1801+
if ($3 < 1) {
1802+
yyerror("hg_scaling_cycle must be at least 1 second");
1803+
YYABORT;
1804+
}
1805+
hg_scaling_cycle=$3; }
1806+
| HG_SCALING_CYCLE EQUAL error {
1807+
yyerror("integer value expected");
1808+
}
1809+
| HG_SHRINK_STEP EQUAL scale_size { IFOR();
1810+
/* scale_size: positive = MB, negated = KB */
1811+
hg_shrink_step = $3 < 0 ?
1812+
(unsigned long)(-$3) << 10 :
1813+
(unsigned long)$3 << 20;
1814+
}
1815+
| HG_SHRINK_STEP EQUAL error {
1816+
yyerror("size expected (number, optional k/m/g)");
1817+
}
1818+
| HG_MEM_CHECK EQUAL NUMBER { IFOR();
1819+
if ($3 < 0 || $3 > 2) {
1820+
yyerror("hg_mem_check must be 0, 1 or 2");
1821+
YYABORT;
1822+
}
1823+
hg_mem_check=$3; }
1824+
| HG_MEM_CHECK EQUAL error {
1825+
yyerror("integer value expected");
1826+
}
16761827
| AUTO_SCALING_CYCLE EQUAL NUMBER { IFOR();
16771828
auto_scaling_cycle=$3; }
16781829
| AUTO_SCALING_CYCLE EQUAL error {

0 commit comments

Comments
 (0)