diff --git a/src/backend/utils/mmgr/vmem_tracker.c b/src/backend/utils/mmgr/vmem_tracker.c index d2b729c97b38..666d72914e39 100644 --- a/src/backend/utils/mmgr/vmem_tracker.c +++ b/src/backend/utils/mmgr/vmem_tracker.c @@ -633,6 +633,12 @@ VmemTracker_ReleaseVmem(int64 toBeFreedRequested) } } +int32 +VmemTracker_GetStartupChunks(void) +{ + return startupChunks; +} + /* * Register the startup memory to vmem tracker. * @@ -670,6 +676,8 @@ VmemTracker_RegisterStartupMemory(int64 bytes) pg_atomic_add_fetch_u32((pg_atomic_uint32 *) segmentVmemChunks, startupChunks); + ResGroupProcAddStartupChunks(startupChunks); + /* * Step 2, check if an OOM error should be raised by allocating 0 chunk. */ @@ -692,6 +700,8 @@ VmemTracker_UnregisterStartupMemory(void) pg_atomic_sub_fetch_u32((pg_atomic_uint32 *) &MySessionState->sessionVmem, startupChunks); + ResGroupProcSubStartupChunks(startupChunks); + trackedBytes -= startupBytes; trackedVmemChunks -= startupChunks; diff --git a/src/backend/utils/resgroup/resgroup.c b/src/backend/utils/resgroup/resgroup.c index 65e52db46ca9..561afcada2e5 100644 --- a/src/backend/utils/resgroup/resgroup.c +++ b/src/backend/utils/resgroup/resgroup.c @@ -1594,6 +1594,30 @@ selfDetachResGroup(ResGroupData *group, ResGroupSlotData *slot) selfUnsetGroup(); } +/* + * Add startup memory before a resgroup is assigned. This memory + * will later be added to resgroup via selfAttachResGroup + */ +void +ResGroupProcAddStartupChunks(int32 chunks) +{ + if (IsResGroupEnabled()) + self->memUsage += chunks; +} + +/* + * Sub startup memory at cleanup. This memory should already been + * subtracted from a resource group via selfDetachResGroup. + * Actually, this is not needed because a running process will always have + * startup memory consumpion, but let it be just for symmetry. + */ +void +ResGroupProcSubStartupChunks(int32 chunks) +{ + if (IsResGroupEnabled()) + self->memUsage -= chunks; +} + /* * Initialize the members of a slot */ diff --git a/src/include/utils/resgroup.h b/src/include/utils/resgroup.h index 87b57d65c66b..789ceb60916b 100644 --- a/src/include/utils/resgroup.h +++ b/src/include/utils/resgroup.h @@ -235,6 +235,9 @@ extern Oid ResGroupGetGroupIdBySessionId(int sessionId); extern char *getCpuSetByRole(const char *cpuset); extern void checkCpuSetByRole(const char *cpuset); +extern void ResGroupProcAddStartupChunks(int32 chunks); +extern void ResGroupProcSubStartupChunks(int32 chunks); + #define LOG_RESGROUP_DEBUG(...) \ do {if (Debug_resource_group) elog(__VA_ARGS__); } while(false); diff --git a/src/include/utils/vmem_tracker.h b/src/include/utils/vmem_tracker.h index 448f3a6bf833..637e53ce0a44 100644 --- a/src/include/utils/vmem_tracker.h +++ b/src/include/utils/vmem_tracker.h @@ -66,6 +66,7 @@ extern void VmemTracker_UnregisterStartupMemory(void); extern void VmemTracker_RequestWaiver(int64 waiver_bytes); extern void VmemTracker_ResetWaiver(void); extern int64 VmemTracker_Fault(int32 reason, int64 arg); +extern int32 VmemTracker_GetStartupChunks(void); extern int32 RedZoneHandler_GetRedZoneLimitChunks(void); extern int32 RedZoneHandler_GetRedZoneLimitMB(void); diff --git a/src/test/isolation2/input/resgroup/resgroup_move_query.source b/src/test/isolation2/input/resgroup/resgroup_move_query.source index d65925e552bc..698870cd5f12 100644 --- a/src/test/isolation2/input/resgroup/resgroup_move_query.source +++ b/src/test/isolation2/input/resgroup/resgroup_move_query.source @@ -11,6 +11,10 @@ -- -- end_matchsubs +-- start_ignore +! gpstop -rai; +-- end_ignore + CREATE OR REPLACE FUNCTION resGroupPalloc(float) RETURNS int AS '@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPalloc' LANGUAGE C READS SQL DATA; @@ -135,7 +139,7 @@ SELECT num_running FROM gp_toolkit.gp_resgroup_status WHERE rsgname='rg_move_que 1&: SELECT pg_sleep(3); 2: SET ROLE role_move_query_mem_small; 2: BEGIN; -2: SELECT hold_memory_by_percent_on_qe(1,0.1); +2: SELECT hold_memory_by_percent_on_qe(1,0.2); 3&: SELECT gp_toolkit.pg_resgroup_move_query(pid, 'rg_move_query') FROM pg_stat_activity WHERE query LIKE '%hold_memory_by_percent_on_qe%' AND rsgname='rg_move_query_mem_small'; 1<: -- connection 1 finished, it will wake up connection 3 @@ -150,7 +154,7 @@ SELECT num_running FROM gp_toolkit.gp_resgroup_status WHERE rsgname='rg_move_que 1: ALTER RESOURCE GROUP rg_move_query SET memory_limit 0; 1: SET ROLE role_move_query_mem_small; 1: BEGIN; -1: SELECT hold_memory_by_percent_on_qe(1,0.1); +1: SELECT hold_memory_by_percent_on_qe(1,0.2); 2: SELECT gp_toolkit.pg_resgroup_move_query(pid, 'rg_move_query') FROM pg_stat_activity WHERE query LIKE '%hold_memory_by_percent_on_qe%' AND rsgname='rg_move_query_mem_small'; 2: SELECT is_session_in_group(pid, 'rg_move_query') FROM pg_stat_activity WHERE query LIKE '%hold_memory_by_percent_on_qe%' AND state = 'idle in transaction'; 1: END; diff --git a/src/test/isolation2/input/resgroup/resgroup_startup_memory.source b/src/test/isolation2/input/resgroup/resgroup_startup_memory.source new file mode 100644 index 000000000000..adecbd969fd9 --- /dev/null +++ b/src/test/isolation2/input/resgroup/resgroup_startup_memory.source @@ -0,0 +1,30 @@ +-- start_ignore +! gpconfig -c runaway_detector_activation_percent -v 20; +! gpstop -rai; +-- end_ignore + +CREATE OR REPLACE FUNCTION resGroupPalloc(float) RETURNS int AS +'@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPalloc' +LANGUAGE C READS SQL DATA; + +CREATE OR REPLACE FUNCTION resGroupPallocIgnoreStartup(float) RETURNS int AS +'@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPallocIgnoreStartup' +LANGUAGE C READS SQL DATA; + +ALTER RESOURCE GROUP default_group SET memory_limit 20; +ALTER RESOURCE GROUP admin_group SET memory_limit 10; +ALTER RESOURCE GROUP admin_group set concurrency 1; + +5: select * from gp_toolkit.gp_resgroup_config; +5q: + +-- This query will be killed by redzone because resGroupPallocIgnoreStartup just allocates +-- the memory size of all resgroup memory. Before startup chunks were considered, a group had no memory tracked +-- at the moment we called resGroupPalloc, so this case shows that now a group tracks startup memory. +5: SELECT resGroupPallocIgnoreStartup(2.39) FROM gp_dist_random('gp_id') WHERE gp_segment_id = 1; +5q: + +-- This won't fail because now resGroupPalloc subtracts startup chunks from the requested amount +-- of memory to keep all previews tests intact. Leaving resGroupPalloc without changes may break them. +5: SELECT resGroupPalloc(2.39) FROM gp_dist_random('gp_id') WHERE gp_segment_id = 1; +5q: diff --git a/src/test/isolation2/isolation2_resgroup_schedule b/src/test/isolation2/isolation2_resgroup_schedule index 065067e14d45..17e191bde5a5 100644 --- a/src/test/isolation2/isolation2_resgroup_schedule +++ b/src/test/isolation2/isolation2_resgroup_schedule @@ -59,4 +59,6 @@ test: resgroup/resgroup_dumpinfo # test larget group id test: resgroup/resgroup_large_group_id +test: resgroup/resgroup_startup_memory + test: resgroup/disable_resgroup diff --git a/src/test/isolation2/output/resgroup/resgroup_bypass.source b/src/test/isolation2/output/resgroup/resgroup_bypass.source index d4c311d316c5..793f100ef57e 100644 --- a/src/test/isolation2/output/resgroup/resgroup_bypass.source +++ b/src/test/isolation2/output/resgroup/resgroup_bypass.source @@ -161,7 +161,7 @@ SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- rg_bypass_test | 0 | 0.0 - rg_bypass_test | 1 | 12.0 + rg_bypass_test | 1 | 24.0 (2 rows) 61: SELECT * FROM eat_memory_on_qd_large; ERROR: Out of memory @@ -202,8 +202,8 @@ BEGIN SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- - rg_bypass_test | 0 | 4.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 0 | 16.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61: SELECT * FROM eat_memory_on_one_slice; count @@ -213,8 +213,8 @@ SELECT * FROM memory_result; SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- - rg_bypass_test | 0 | 8.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 0 | 20.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61: SELECT * FROM eat_memory_on_one_slice; ERROR: Out of memory (seg0 slice1 127.0.0.1:25432 pid=336) @@ -234,7 +234,7 @@ SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- rg_bypass_test | 0 | 0.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61q: ... @@ -256,8 +256,8 @@ BEGIN SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- - rg_bypass_test | 0 | 4.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 0 | 16.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61: SELECT * FROM eat_memory_on_slices; count @@ -267,8 +267,8 @@ SELECT * FROM memory_result; SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- - rg_bypass_test | 0 | 8.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 0 | 20.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61: SELECT * FROM eat_memory_on_slices; ERROR: Out of memory (seg0 slice2 127.0.0.1:25432 pid=354) @@ -288,7 +288,7 @@ SELECT * FROM memory_result; rsgname | ismaster | avg_mem ----------------+----------+--------- rg_bypass_test | 0 | 0.0 - rg_bypass_test | 1 | 0.0 + rg_bypass_test | 1 | 12.0 (2 rows) 61q: ... diff --git a/src/test/isolation2/output/resgroup/resgroup_memory_statistic.source b/src/test/isolation2/output/resgroup/resgroup_memory_statistic.source index 052db8cdced2..6b679bb59865 100644 --- a/src/test/isolation2/output/resgroup/resgroup_memory_statistic.source +++ b/src/test/isolation2/output/resgroup/resgroup_memory_statistic.source @@ -80,7 +80,7 @@ SELECT * FROM memory_result; rsgname | ismaster | avg_mem -----------------+----------+--------- rg1_memory_test | 0 | 0.0 - rg1_memory_test | 1 | 20.0 + rg1_memory_test | 1 | 30.0 rg2_memory_test | 0 | 0.0 rg2_memory_test | 1 | 0.0 (4 rows) @@ -144,8 +144,8 @@ BEGIN SELECT * FROM memory_result; rsgname | ismaster | avg_mem -----------------+----------+--------- - rg1_memory_test | 0 | 20.0 - rg1_memory_test | 1 | 0.0 + rg1_memory_test | 0 | 30.0 + rg1_memory_test | 1 | 10.0 rg2_memory_test | 0 | 0.0 rg2_memory_test | 1 | 0.0 (4 rows) diff --git a/src/test/isolation2/output/resgroup/resgroup_move_query.source b/src/test/isolation2/output/resgroup/resgroup_move_query.source index 02587e1575b8..1918d6fc348b 100644 --- a/src/test/isolation2/output/resgroup/resgroup_move_query.source +++ b/src/test/isolation2/output/resgroup/resgroup_move_query.source @@ -11,6 +11,10 @@ -- -- end_matchsubs +-- start_ignore +! gpstop -rai; +-- end_ignore + CREATE OR REPLACE FUNCTION resGroupPalloc(float) RETURNS int AS '@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPalloc' LANGUAGE C READS SQL DATA; CREATE @@ -185,7 +189,7 @@ SET SET 2: BEGIN; BEGIN -2: SELECT hold_memory_by_percent_on_qe(1,0.1); +2: SELECT hold_memory_by_percent_on_qe(1,0.2); hold_memory_by_percent_on_qe ------------------------------ 0 @@ -220,7 +224,7 @@ ALTER SET 1: BEGIN; BEGIN -1: SELECT hold_memory_by_percent_on_qe(1,0.1); +1: SELECT hold_memory_by_percent_on_qe(1,0.2); hold_memory_by_percent_on_qe ------------------------------ 0 diff --git a/src/test/isolation2/output/resgroup/resgroup_startup_memory.source b/src/test/isolation2/output/resgroup/resgroup_startup_memory.source new file mode 100644 index 000000000000..3a765922e775 --- /dev/null +++ b/src/test/isolation2/output/resgroup/resgroup_startup_memory.source @@ -0,0 +1,41 @@ +-- start_ignore +! gpconfig -c runaway_detector_activation_percent -v 20; +! gpstop -rai; +-- end_ignore + +CREATE OR REPLACE FUNCTION resGroupPalloc(float) RETURNS int AS '@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPalloc' LANGUAGE C READS SQL DATA; +CREATE + +CREATE OR REPLACE FUNCTION resGroupPallocIgnoreStartup(float) RETURNS int AS '@abs_builddir@/../regress/regress@DLSUFFIX@', 'resGroupPallocIgnoreStartup' LANGUAGE C READS SQL DATA; +CREATE + +ALTER RESOURCE GROUP default_group SET memory_limit 20; +ALTER +ALTER RESOURCE GROUP admin_group SET memory_limit 10; +ALTER +ALTER RESOURCE GROUP admin_group set concurrency 1; +ALTER + +5: select * from gp_toolkit.gp_resgroup_config; + groupid | groupname | concurrency | cpu_rate_limit | memory_limit | memory_shared_quota | memory_spill_ratio | memory_auditor | cpuset +---------+---------------+-------------+----------------+--------------+---------------------+--------------------+----------------+-------- + 6437 | default_group | 20 | 30 | 20 | 80 | 10 | vmtracker | -1 + 6438 | admin_group | 1 | 10 | 10 | 80 | 10 | vmtracker | -1 +(2 rows) +5q: ... + +-- This query will be killed by redzone because resGroupPallocIgnoreStartup just allocates +-- the memory size of all resgroup memory. Before startup chunks were considered, a group had no memory tracked +-- at the moment we called resGroupPalloc, so this case shows that now a group tracks startup memory. +5: SELECT resGroupPallocIgnoreStartup(2.39) FROM gp_dist_random('gp_id') WHERE gp_segment_id = 1; +ERROR: Canceling query because of high VMEM usage. current group id is 6438, group memory usage 175 MB, group shared memory quota is 55 MB, slot memory quota is 13 MB, global freechunks memory is 371 MB, global safe memory threshold is 382 MB (runaway_cleaner.c:197) (seg1 slice1 10.92.43.77:6003 pid=29522) (runaway_cleaner.c:197) +5q: ... + +-- This won't fail because now resGroupPalloc subtracts startup chunks from the requested amount +-- of memory to keep all previews tests intact. Leaving resGroupPalloc without changes may break them. +5: SELECT resGroupPalloc(2.39) FROM gp_dist_random('gp_id') WHERE gp_segment_id = 1; + resgrouppalloc +---------------- + 0 +(1 row) +5q: ... diff --git a/src/test/isolation2/sql/.gitignore b/src/test/isolation2/sql/.gitignore index 52364f5a4b8c..e3505417515a 100644 --- a/src/test/isolation2/sql/.gitignore +++ b/src/test/isolation2/sql/.gitignore @@ -10,3 +10,4 @@ resgroup_bypass.sql resgroup_cpuset.sql gp_collation.sql distributed_snapshot.sql +resgroup_startup_memory.sql diff --git a/src/test/regress/regress_gp.c b/src/test/regress/regress_gp.c index 988a9a0d2252..4ee4e4b04b46 100644 --- a/src/test/regress/regress_gp.c +++ b/src/test/regress/regress_gp.c @@ -50,10 +50,12 @@ #include "libpq/hba.h" #include "utils/builtins.h" #include "utils/geo_decls.h" +#include "utils/gp_alloc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/resource_manager.h" #include "utils/timestamp.h" +#include "utils/vmem_tracker.h" /* table_functions test */ extern Datum multiset_example(PG_FUNCTION_ARGS); @@ -78,6 +80,7 @@ extern Datum userdata_project(PG_FUNCTION_ARGS); extern Datum checkResourceQueueMemoryLimits(PG_FUNCTION_ARGS); extern Datum repeatPalloc(PG_FUNCTION_ARGS); extern Datum resGroupPalloc(PG_FUNCTION_ARGS); +extern Datum resGroupPallocIgnoreStartup(PG_FUNCTION_ARGS); /* Gang management test support */ extern Datum gangRaiseInfo(PG_FUNCTION_ARGS); @@ -628,21 +631,21 @@ repeatPalloc(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } -PG_FUNCTION_INFO_V1(resGroupPalloc); -Datum -resGroupPalloc(PG_FUNCTION_ARGS) -{ - float ratio = PG_GETARG_FLOAT8(0); +static bool startupConsidered = false; +static void +resGroupPallocImpl(float ratio, bool considerStartup) { int memLimit, slotQuota, sharedQuota; int size; int count; int i; - if (!IsResGroupEnabled()) - PG_RETURN_INT32(0); - ResGroupGetMemInfo(&memLimit, &slotQuota, &sharedQuota); - size = ceilf(memLimit * ratio); + + if (considerStartup && !startupConsidered) + size = ceilf(memLimit * ratio) - VmemTracker_GetStartupChunks(); + else + size = ceilf(memLimit * ratio); + count = size / 512; for (i = 0; i < count; i++) MemoryContextAlloc(TopMemoryContext, 512 * 1024 * 1024); @@ -650,6 +653,35 @@ resGroupPalloc(PG_FUNCTION_ARGS) size %= 512; MemoryContextAlloc(TopMemoryContext, size * 1024 * 1024); + if (considerStartup && !startupConsidered) + startupConsidered = true; +} + +/* + * This function is a copy of resGroupPalloc that existed before startup chunks were considered + * It's needed for the tests, but we can't use the old name because we need + * to maintain compatibility with the old tests which don't expect resGroupPalloc + * to allocate extra memory which is startupChunks + */ +PG_FUNCTION_INFO_V1(resGroupPallocIgnoreStartup); +Datum +resGroupPallocIgnoreStartup(PG_FUNCTION_ARGS) +{ + float ratio = PG_GETARG_FLOAT8(0); + + resGroupPallocImpl(ratio, false); + + PG_RETURN_INT32(0); +} + +PG_FUNCTION_INFO_V1(resGroupPalloc); +Datum +resGroupPalloc(PG_FUNCTION_ARGS) +{ + float ratio = PG_GETARG_FLOAT8(0); + + resGroupPallocImpl(ratio, true); + PG_RETURN_INT32(0); }