From f44323f5fb3ee0991bbf7e917dde586c6d155718 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Fri, 12 Jun 2026 17:52:06 +0800 Subject: [PATCH 01/12] Remove unnecessary vacuum_set_xid_limits calls for AO/AOCO tables AO/AOCO tables have no per-tuple xmin/xmax -- visibility is managed via visibility map at segment level, not per-tuple transaction IDs. The freeze limits computed by vacuum_set_xid_limits are meaningless for AO tables. Worse, passing MultiXactCutoff to vac_update_relstats (vacuum) or swap_relation_files (CLUSTER) incorrectly sets relminmxid on AO tables (whose relminmxid should remain InvalidMultiXactId), causing them to unnecessarily participate in database-wide datminmxid calculation. Fix by: - vacuum_ao.c: remove vacuum_set_xid_limits call, pass Invalid values directly to vac_update_relstats - appendonlyam_handler.c / aocsam_handler.c: remove vacuum_set_xid_limits call in copy_for_cluster, return Invalid values to caller - cluster.c: relax MultiXactId assert to allow InvalidMultiXactId, and reset relminmxid to InvalidMultiXactId for AO tables (matching the existing relfrozenxid override) vacuum_set_xid_limits was a pre-PG16 API kept only for AO callers. With all callers removed, delete the function and its declaration. --- src/backend/access/aocs/aocsam_handler.c | 29 +-- .../access/appendonly/appendonlyam_handler.c | 29 +-- src/backend/commands/cluster.c | 13 +- src/backend/commands/vacuum.c | 199 ------------------ src/backend/commands/vacuum_ao.c | 24 +-- src/include/commands/vacuum.h | 9 - 6 files changed, 27 insertions(+), 276 deletions(-) diff --git a/src/backend/access/aocs/aocsam_handler.c b/src/backend/access/aocs/aocsam_handler.c index 5cbf2015c64..4dc7d541c5f 100644 --- a/src/backend/access/aocs/aocsam_handler.c +++ b/src/backend/access/aocs/aocsam_handler.c @@ -1462,8 +1462,6 @@ aoco_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, int natts; Datum *values; bool *isnull; - TransactionId FreezeXid; - MultiXactId MultiXactCutoff; Tuplesortstate *tuplesort; PGRUsage ru0; @@ -1523,29 +1521,12 @@ aoco_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber); /* - * Compute sane values for FreezeXid and CutoffMulti with regular - * VACUUM machinery to avoidconfising existing CLUSTER code. + * AO/AOCO tables have no per-tuple xmin/xmax, so freeze limits don't + * apply. Return Invalid values so that relfrozenxid and relminmxid + * remain unchanged after CLUSTER. */ - vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0, - &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff, - NULL); - - /* - * FreezeXid will become the table's new relfrozenxid, and that mustn't go - * backwards, so take the max. - */ - if (TransactionIdPrecedes(FreezeXid, OldHeap->rd_rel->relfrozenxid)) - FreezeXid = OldHeap->rd_rel->relfrozenxid; - - /* - * MultiXactCutoff, similarly, shouldn't go backwards either. - */ - if (MultiXactIdPrecedes(MultiXactCutoff, OldHeap->rd_rel->relminmxid)) - MultiXactCutoff = OldHeap->rd_rel->relminmxid; - - /* return selected values to caller */ - *xid_cutoff = FreezeXid; - *multi_cutoff = MultiXactCutoff; + *xid_cutoff = InvalidTransactionId; + *multi_cutoff = InvalidMultiXactId; tuplesort = tuplesort_begin_cluster(oldTupDesc, OldIndex, maintenance_work_mem, NULL, false); diff --git a/src/backend/access/appendonly/appendonlyam_handler.c b/src/backend/access/appendonly/appendonlyam_handler.c index cd37c0bbacd..cae12e110ff 100644 --- a/src/backend/access/appendonly/appendonlyam_handler.c +++ b/src/backend/access/appendonly/appendonlyam_handler.c @@ -1317,8 +1317,6 @@ appendonly_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, int natts; Datum *values; bool *isnull; - TransactionId FreezeXid; - MultiXactId MultiXactCutoff; Tuplesortstate *tuplesort; PGRUsage ru0; @@ -1380,29 +1378,12 @@ appendonly_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber); /* - * Compute sane values for FreezeXid and CutoffMulti with regular - * VACUUM machinery to avoidconfising existing CLUSTER code. + * AO/AOCO tables have no per-tuple xmin/xmax, so freeze limits don't + * apply. Return Invalid values so that relfrozenxid and relminmxid + * remain unchanged after CLUSTER. */ - vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0, - &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff, - NULL); - - /* - * FreezeXid will become the table's new relfrozenxid, and that mustn't go - * backwards, so take the max. - */ - if (TransactionIdPrecedes(FreezeXid, OldHeap->rd_rel->relfrozenxid)) - FreezeXid = OldHeap->rd_rel->relfrozenxid; - - /* - * MultiXactCutoff, similarly, shouldn't go backwards either. - */ - if (MultiXactIdPrecedes(MultiXactCutoff, OldHeap->rd_rel->relminmxid)) - MultiXactCutoff = OldHeap->rd_rel->relminmxid; - - /* return selected values to caller */ - *xid_cutoff = FreezeXid; - *multi_cutoff = MultiXactCutoff; + *xid_cutoff = InvalidTransactionId; + *multi_cutoff = InvalidMultiXactId; tuplesort = tuplesort_begin_cluster(oldTupDesc, OldIndex, maintenance_work_mem, NULL, false); diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index e31fe4cef8e..a3d2ad87bfb 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1486,17 +1486,24 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class, Assert(!TransactionIdIsValid(frozenXid) || TransactionIdIsNormal(frozenXid)); relform1->relfrozenxid = frozenXid; - Assert(MultiXactIdIsValid(cutoffMulti)); + Assert(!MultiXactIdIsValid(cutoffMulti) || + MultiXactIdPrecedesOrEquals(FirstMultiXactId, cutoffMulti)); relform1->relminmxid = cutoffMulti; } /* - * Cloudberry: append-optimized tables do not have a valid relfrozenxid. - * Overwrite the entry for both relations. + * Cloudberry: append-optimized tables do not have a valid relfrozenxid + * or relminmxid. Overwrite the entry for both relations. */ if (relform1->relkind != RELKIND_INDEX && IsAccessMethodAO(relform1->relam)) + { relform1->relfrozenxid = InvalidTransactionId; + relform1->relminmxid = InvalidMultiXactId; + } if (relform2->relkind != RELKIND_INDEX && IsAccessMethodAO(relform2->relam)) + { relform2->relfrozenxid = InvalidTransactionId; + relform2->relminmxid = InvalidMultiXactId; + } /* swap size statistics too, since new rel has freshly-updated stats */ if (swap_stats) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 80585a878a7..f4ba5615d5a 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -3914,202 +3914,3 @@ vac_cmp_itemptr(const void *left, const void *right) return 0; } - -void -vacuum_set_xid_limits(Relation rel, - int freeze_min_age, - int freeze_table_age, - int multixact_freeze_min_age, - int multixact_freeze_table_age, - TransactionId *oldestXmin, - TransactionId *freezeLimit, - TransactionId *xidFullScanLimit, - MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit) -{ - int freezemin; - int mxid_freezemin; - int effective_multixact_freeze_max_age; - TransactionId limit; - TransactionId safeLimit; - MultiXactId oldestMxact; - MultiXactId mxactLimit; - MultiXactId safeMxactLimit; - - /* - * We can always ignore processes running lazy vacuum. This is because we - * use these values only for deciding which tuples we must keep in the - * tables. Since lazy vacuum doesn't write its XID anywhere (usually no - * XID assigned), it's safe to ignore it. In theory it could be - * problematic to ignore lazy vacuums in a full vacuum, but keep in mind - * that only one vacuum process can be working on a particular table at - * any time, and that each vacuum is always an independent transaction. - */ - *oldestXmin = GetOldestNonRemovableTransactionId(rel); - - if (OldSnapshotThresholdActive()) - { - TransactionId limit_xmin; - TimestampTz limit_ts; - - if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel, - &limit_xmin, &limit_ts)) - { - /* - * TODO: We should only set the threshold if we are pruning on the - * basis of the increased limits. Not as crucial here as it is - * for opportunistic pruning (which often happens at a much higher - * frequency), but would still be a significant improvement. - */ - SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin); - *oldestXmin = limit_xmin; - } - } - - Assert(TransactionIdIsNormal(*oldestXmin)); - - /* - * Determine the minimum freeze age to use: as specified by the caller, or - * vacuum_freeze_min_age, but in any case not more than half - * autovacuum_freeze_max_age, so that autovacuums to prevent XID - * wraparound won't occur too frequently. - */ - freezemin = freeze_min_age; - if (freezemin < 0) - freezemin = vacuum_freeze_min_age; - freezemin = Min(freezemin, autovacuum_freeze_max_age / 2); - Assert(freezemin >= 0); - - /* - * Compute the cutoff XID, being careful not to generate a "permanent" XID - */ - limit = *oldestXmin - freezemin; - if (!TransactionIdIsNormal(limit)) - limit = FirstNormalTransactionId; - - /* - * If oldestXmin is very far back (in practice, more than - * autovacuum_freeze_max_age / 2 XIDs old), complain and force a minimum - * freeze age of zero. - */ - safeLimit = ReadNextTransactionId() - autovacuum_freeze_max_age; - if (!TransactionIdIsNormal(safeLimit)) - safeLimit = FirstNormalTransactionId; - - if (TransactionIdPrecedes(limit, safeLimit)) - { - ereport(WARNING, - (errmsg("oldest xmin is far in the past"), - errhint("Close open transactions soon to avoid wraparound problems.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); - limit = *oldestXmin; - } - - *freezeLimit = limit; - - /* - * Compute the multixact age for which freezing is urgent. This is - * normally autovacuum_multixact_freeze_max_age, but may be less if we are - * short of multixact member space. - */ - effective_multixact_freeze_max_age = MultiXactMemberFreezeThreshold(); - - /* - * Determine the minimum multixact freeze age to use: as specified by - * caller, or vacuum_multixact_freeze_min_age, but in any case not more - * than half effective_multixact_freeze_max_age, so that autovacuums to - * prevent MultiXact wraparound won't occur too frequently. - */ - mxid_freezemin = multixact_freeze_min_age; - if (mxid_freezemin < 0) - mxid_freezemin = vacuum_multixact_freeze_min_age; - mxid_freezemin = Min(mxid_freezemin, - effective_multixact_freeze_max_age / 2); - Assert(mxid_freezemin >= 0); - - /* compute the cutoff multi, being careful to generate a valid value */ - oldestMxact = GetOldestMultiXactId(); - mxactLimit = oldestMxact - mxid_freezemin; - if (mxactLimit < FirstMultiXactId) - mxactLimit = FirstMultiXactId; - - safeMxactLimit = - ReadNextMultiXactId() - effective_multixact_freeze_max_age; - if (safeMxactLimit < FirstMultiXactId) - safeMxactLimit = FirstMultiXactId; - - if (MultiXactIdPrecedes(mxactLimit, safeMxactLimit)) - { - ereport(WARNING, - (errmsg("oldest multixact is far in the past"), - errhint("Close open transactions with multixacts soon to avoid wraparound problems."))); - /* Use the safe limit, unless an older mxact is still running */ - if (MultiXactIdPrecedes(oldestMxact, safeMxactLimit)) - mxactLimit = oldestMxact; - else - mxactLimit = safeMxactLimit; - } - - *multiXactCutoff = mxactLimit; - - if (xidFullScanLimit != NULL) - { - int freezetable; - - Assert(mxactFullScanLimit != NULL); - - /* - * Determine the table freeze age to use: as specified by the caller, - * or vacuum_freeze_table_age, but in any case not more than - * autovacuum_freeze_max_age * 0.95, so that if you have e.g nightly - * VACUUM schedule, the nightly VACUUM gets a chance to freeze tuples - * before anti-wraparound autovacuum is launched. - */ - freezetable = freeze_table_age; - if (freezetable < 0) - freezetable = vacuum_freeze_table_age; - freezetable = Min(freezetable, autovacuum_freeze_max_age * 0.95); - Assert(freezetable >= 0); - - /* - * Compute XID limit causing a full-table vacuum, being careful not to - * generate a "permanent" XID. - */ - limit = ReadNextTransactionId() - freezetable; - if (!TransactionIdIsNormal(limit)) - limit = FirstNormalTransactionId; - - *xidFullScanLimit = limit; - - /* - * Similar to the above, determine the table freeze age to use for - * multixacts: as specified by the caller, or - * vacuum_multixact_freeze_table_age, but in any case not more than - * autovacuum_multixact_freeze_table_age * 0.95, so that if you have - * e.g. nightly VACUUM schedule, the nightly VACUUM gets a chance to - * freeze multixacts before anti-wraparound autovacuum is launched. - */ - freezetable = multixact_freeze_table_age; - if (freezetable < 0) - freezetable = vacuum_multixact_freeze_table_age; - freezetable = Min(freezetable, - effective_multixact_freeze_max_age * 0.95); - Assert(freezetable >= 0); - - /* - * Compute MultiXact limit causing a full-table vacuum, being careful - * to generate a valid MultiXact value. - */ - mxactLimit = ReadNextMultiXactId() - freezetable; - if (mxactLimit < FirstMultiXactId) - mxactLimit = FirstMultiXactId; - - *mxactFullScanLimit = mxactLimit; - } - else - { - Assert(mxactFullScanLimit == NULL); - } -} - - diff --git a/src/backend/commands/vacuum_ao.c b/src/backend/commands/vacuum_ao.c index dd0522f1986..075c73fb1c1 100644 --- a/src/backend/commands/vacuum_ao.c +++ b/src/backend/commands/vacuum_ao.c @@ -245,11 +245,6 @@ ao_vacuum_rel_post_cleanup(Relation onerel, VacuumParams *params, BufferAccessSt BlockNumber total_file_segs; int elevel; int options = params->options; - TransactionId OldestXmin; - TransactionId FreezeLimit; - MultiXactId MultiXactCutoff; - TransactionId xidFullScanLimit; - MultiXactId mxactFullScanLimit; if (options & VACOPT_VERBOSE) elevel = INFO; @@ -288,16 +283,11 @@ ao_vacuum_rel_post_cleanup(Relation onerel, VacuumParams *params, BufferAccessSt &relhasindex, &total_file_segs); - /* MERGE16_FIXME: How to set limits for ao */ - vacuum_set_xid_limits(onerel, - params->freeze_min_age, - params->freeze_table_age, - params->multixact_freeze_min_age, - params->multixact_freeze_table_age, - &OldestXmin, &FreezeLimit, &xidFullScanLimit, - &MultiXactCutoff, &mxactFullScanLimit); - - /* Causion: AO/AOCO use relallvisible to represent total segment file count */ + /* + * AO/AOCO tables have no per-tuple xmin/xmax, so freeze limits don't + * apply. Pass InvalidTransactionId/InvalidMultiXactId to keep + * relfrozenxid and relminmxid unchanged. + */ vac_update_relstats(onerel, relpages, reltuples, @@ -305,8 +295,8 @@ ao_vacuum_rel_post_cleanup(Relation onerel, VacuumParams *params, BufferAccessSt Heap's 'all visible pages', use this field to represent AO/AOCO's total segment file count */ relhasindex, - FreezeLimit, - MultiXactCutoff, + InvalidTransactionId, + InvalidMultiXactId, NULL, NULL, false, diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index d700f4a72cc..431cd7221a8 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -491,15 +491,6 @@ extern Size vac_max_items_to_alloc_size(int max_items); /* In postmaster/autovacuum.c */ extern void AutoVacuumUpdateCostLimit(void); extern void VacuumUpdateCosts(void); -extern void vacuum_set_xid_limits(Relation rel, - int freeze_min_age, int freeze_table_age, - int multixact_freeze_min_age, - int multixact_freeze_table_age, - TransactionId *oldestXmin, - TransactionId *freezeLimit, - TransactionId *xidFullScanLimit, - MultiXactId *multiXactCutoff, - MultiXactId *mxactFullScanLimit); /* in commands/vacuumparallel.c */ extern ParallelVacuumState *parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, int nrequested_workers, From 2e6d708a028c677795c9543c31f64992951e306c Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 15 Jun 2026 10:19:45 +0800 Subject: [PATCH 02/12] Remove MERGE16_FIXME in PartitionSelector and dead declarations The CreatePartitionPruneState() call in nodePartitionSelector.c is correct -- PartitionSelector only needs the pruning data structure, not the initial pruning and subplan map renumbering that ExecInitPartitionPruning() adds on top. Remove the incorrect FIXME. Also remove two dead declarations in execPartition.h: - ExecCreatePartitionPruneState: renamed to CreatePartitionPruneState in PG15 (commit 297daa9d435), declaration was never cleaned up - ExecFindInitialMatchingSubPlans: folded into ExecFindMatchingSubPlans in the same refactor, declaration was never cleaned up --- src/backend/executor/nodePartitionSelector.c | 1 - src/include/executor/execPartition.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/backend/executor/nodePartitionSelector.c b/src/backend/executor/nodePartitionSelector.c index 7999a1a4d71..1a1e3affa85 100644 --- a/src/backend/executor/nodePartitionSelector.c +++ b/src/backend/executor/nodePartitionSelector.c @@ -101,7 +101,6 @@ ExecInitPartitionSelector(PartitionSelector *node, EState *estate, int eflags) outerPlanState(psstate) = ExecInitNode(outerPlan(node), estate, eflags); /* Create the working data structure for pruning. */ - /* MERGE16_FIXME: This use of ExecInitPartitionPruning may be incorrect */ psstate->prune_state = CreatePartitionPruneState(&psstate->ps, node->part_prune_info); return psstate; diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h index 22c4fc9a5e6..91bc97db8c6 100644 --- a/src/include/executor/execPartition.h +++ b/src/include/executor/execPartition.h @@ -130,14 +130,10 @@ extern ResultRelInfo *ExecFindPartition(ModifyTableState *mtstate, EState *estate); extern void ExecCleanupTupleRouting(ModifyTableState *mtstate, PartitionTupleRouting *proute); -extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate, - PartitionPruneInfo *partitionpruneinfo); extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate, bool initial_prune, EState *estate, int nplans, List *join_prune_paramids); -extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate, - int nsubplans); extern int get_partition_for_tuple(PartitionKey key, PartitionDesc partdesc, Datum *values, bool *isnull); From 0678c445eca0194e5072e200290416886ed39ef0 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 15 Jun 2026 14:42:07 +0800 Subject: [PATCH 03/12] Fix MERGE16_FIXME: add UNSAFE_HAS_SUBPLAN flag for qual pushdown The subplan check in check_output_expressions was incorrectly using UNSAFE_NOTIN_PARTITIONBY_CLAUSE, which only prevents normal pushdown but still allows the qual to be pushed as a window run condition. Subplans in output expressions should completely block pushdown in Cloudberry's distributed execution model. Add a dedicated UNSAFE_HAS_SUBPLAN flag and include it in the fully unsafe set in qual_is_pushdown_safe, so quals referencing output columns containing subplans are never pushed down. --- src/backend/optimizer/path/allpaths.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 76ce1e8fbea..6bb0f9a92a5 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -74,6 +74,7 @@ bool gp_enable_sort_limit = false; #define UNSAFE_NOTIN_DISTINCTON_CLAUSE (1 << 2) #define UNSAFE_NOTIN_PARTITIONBY_CLAUSE (1 << 3) #define UNSAFE_TYPE_MISMATCH (1 << 4) +#define UNSAFE_HAS_SUBPLAN (1 << 5) /* results of subquery_is_pushdown_safe */ typedef struct pushdown_safety_info @@ -4714,11 +4715,10 @@ check_output_expressions(Query *subquery, pushdown_safety_info *safetyInfo) continue; } - /* Refuse subplans */ + /* Refuse subplans (Cloudberry-specific, see UNSAFE_HAS_SUBPLAN) */ if (contain_subplans((Node *) tle->expr)) { - /*.MERGE16_FIXME: should we add a new unsafe type? */ - safetyInfo->unsafeFlags[tle->resno] |= UNSAFE_NOTIN_PARTITIONBY_CLAUSE; + safetyInfo->unsafeFlags[tle->resno] |= UNSAFE_HAS_SUBPLAN; continue; } } @@ -4896,7 +4896,8 @@ qual_is_pushdown_safe(Query *subquery, Index rti, RestrictInfo *rinfo, { if (safetyInfo->unsafeFlags[var->varattno] & (UNSAFE_HAS_VOLATILE_FUNC | UNSAFE_HAS_SET_FUNC | - UNSAFE_NOTIN_DISTINCTON_CLAUSE | UNSAFE_TYPE_MISMATCH)) + UNSAFE_NOTIN_DISTINCTON_CLAUSE | UNSAFE_TYPE_MISMATCH | + UNSAFE_HAS_SUBPLAN)) { safe = PUSHDOWN_UNSAFE; break; From b72f61e365dce7dc68f56d5fa431fc463424359a Mon Sep 17 00:00:00 2001 From: liushengsong Date: Tue, 16 Jun 2026 10:03:11 +0800 Subject: [PATCH 04/12] Fix PAX alter_distribution_policy test: use matchsubs to mask cluster.c line number --- .../test/regress/expected/alter_distribution_policy.out | 8 ++++++-- .../expected/alter_distribution_policy_optimizer.out | 8 ++++++-- .../src/test/regress/sql/alter_distribution_policy.sql | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy.out b/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy.out index be070815b61..1f4d55e0b8a 100644 --- a/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy.out +++ b/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy.out @@ -1,3 +1,7 @@ +-- start_matchsubs +-- m/\(cluster.c:\d+\)/ +-- s/\(cluster.c:\d+\)/\(cluster.c:###\)/ +-- end_matchsubs -- ALTER TABLE ... SET DISTRIBUTED BY -- This is the main interface for system expansion \set DATA values(1, 2), (2, 3), (3, 4) @@ -171,7 +175,7 @@ ERROR: permission denied: "pg_class" is a system catalog create table atsdb (i int, j text) distributed by (j); insert into atsdb select i, i::text from generate_series(1, 10) i; alter table atsdb set with(appendonly = true); -ERROR: PAX not allow swap relation files for different AM (cluster.c:1535) +ERROR: PAX not allow swap relation files for different AM (cluster.c:###) select relname, segrelid != 0, reloptions from pg_class, pg_appendonly where pg_class.oid = 'atsdb'::regclass and relid = pg_class.oid; relname | ?column? | reloptions @@ -316,7 +320,7 @@ select * from distcheck where rel = 'atsdb'; alter table atsdb drop column n; alter table atsdb set with(appendonly = true, compresslevel = 3); -ERROR: PAX not allow swap relation files for different AM (cluster.c:1535) +ERROR: PAX not allow swap relation files for different AM (cluster.c:###) select relname, segrelid != 0, reloptions from pg_class, pg_appendonly where pg_class.oid = 'atsdb'::regclass and relid = pg_class.oid; relname | ?column? | reloptions diff --git a/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy_optimizer.out b/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy_optimizer.out index df30a5d8f05..0eafd5f8854 100644 --- a/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/alter_distribution_policy_optimizer.out @@ -1,3 +1,7 @@ +-- start_matchsubs +-- m/\(cluster.c:\d+\)/ +-- s/\(cluster.c:\d+\)/\(cluster.c:###\)/ +-- end_matchsubs -- ALTER TABLE ... SET DISTRIBUTED BY -- This is the main interface for system expansion \set DATA values(1, 2), (2, 3), (3, 4) @@ -171,7 +175,7 @@ ERROR: permission denied: "pg_class" is a system catalog create table atsdb (i int, j text) distributed by (j); insert into atsdb select i, i::text from generate_series(1, 10) i; alter table atsdb set with(appendonly = true); -ERROR: PAX not allow swap relation files for different AM (cluster.c:1535) +ERROR: PAX not allow swap relation files for different AM (cluster.c:###) select relname, segrelid != 0, reloptions from pg_class, pg_appendonly where pg_class.oid = 'atsdb'::regclass and relid = pg_class.oid; relname | ?column? | reloptions @@ -316,7 +320,7 @@ select * from distcheck where rel = 'atsdb'; alter table atsdb drop column n; alter table atsdb set with(appendonly = true, compresslevel = 3); -ERROR: PAX not allow swap relation files for different AM (cluster.c:1535) +ERROR: PAX not allow swap relation files for different AM (cluster.c:###) select relname, segrelid != 0, reloptions from pg_class, pg_appendonly where pg_class.oid = 'atsdb'::regclass and relid = pg_class.oid; relname | ?column? | reloptions diff --git a/contrib/pax_storage/src/test/regress/sql/alter_distribution_policy.sql b/contrib/pax_storage/src/test/regress/sql/alter_distribution_policy.sql index feade3ed93d..6345ae987ec 100644 --- a/contrib/pax_storage/src/test/regress/sql/alter_distribution_policy.sql +++ b/contrib/pax_storage/src/test/regress/sql/alter_distribution_policy.sql @@ -1,3 +1,7 @@ +-- start_matchsubs +-- m/\(cluster.c:\d+\)/ +-- s/\(cluster.c:\d+\)/\(cluster.c:###\)/ +-- end_matchsubs -- ALTER TABLE ... SET DISTRIBUTED BY -- This is the main interface for system expansion \set DATA values(1, 2), (2, 3), (3, 4) From cd212a0c123dca8a3291ad26f2492ed4a6555dd8 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 22 Jun 2026 10:13:41 +0800 Subject: [PATCH 05/12] Re-enable pgstat temp file reporting and fix SIGSEGV in ReportTemporaryFileUsage Re-enable temporary file size reporting to pgstat and the associated Assert in FileClose. Fix a SIGSEGV in ReportTemporaryFileUsage that occurred during process exit when the resource owner was already released. --- src/backend/storage/file/fd.c | 12 ++++++++---- src/backend/utils/activity/pgstat.c | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index ebbecff523f..407bb90cec2 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -1576,10 +1576,14 @@ FileAccess(File file) static void ReportTemporaryFileUsage(const char *path, off_t size) { - /* MERGE16_FIXME: Now the pgstat has not worked, so disable the report first */ - return; - - pgstat_report_tempfile(size); + /* + * pgstat_report_tempfile() accesses shared memory via dshash, which + * may already be detached during process exit cleanup. Calling it + * from PathNameDeleteTemporaryDir's walkdir causes SIGSEGV in + * dshash_find(). Guard with IsUnderPostmaster and proc_exit_inprogress. + */ + if (!proc_exit_inprogress) + pgstat_report_tempfile(size); if (log_temp_files >= 0) { diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index a43dcb75398..beaeb669266 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -1301,8 +1301,7 @@ pgstat_get_kind_info(PgStat_Kind kind) void pgstat_assert_is_up(void) { - /* MERGE16_FIXME: Now the pgstat has not worked, so disable the assert first */ -// Assert(pgstat_is_initialized && !pgstat_is_shutdown); + Assert(pgstat_is_initialized && !pgstat_is_shutdown); } #endif From 6fabcc7d40fc3b52840f8892841660b7e695e48d Mon Sep 17 00:00:00 2001 From: liushengsong Date: Wed, 17 Jun 2026 16:15:34 +0800 Subject: [PATCH 06/12] Remove MERGE16_FIXME: delete dead requiredPerms stripping code in exec_mpp_query The commented-out code stripped write permissions from RTEs on non-root slices. This is unnecessary because InitPlan already skips permission checks on non-writer segments (execMain.c:1821). Additionally, PG16 moved requiredPerms from RTE to RTEPermissionInfo, making the original code incompatible. --- src/backend/tcop/postgres.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 0a390048819..8eba8a6d227 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -1300,28 +1300,6 @@ exec_mpp_query(const char *query_string, elog(ERROR, "MPPEXEC: received non-DML Plan"); commandType = plan->commandType; - // MERGE16_FIXME: Check if wo should remove requiredPerms in Query -// if ( slice ) -// { -// /* Non root slices don't need update privileges. */ -// if (sliceTable->localSlice != slice->rootIndex) -// { -// ListCell *rtcell; -// RangeTblEntry *rte; -// RTEPermissionInfo *rte_permission; -// AclMode removeperms = ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_SELECT_FOR_UPDATE; -// -// /* Just reading, so don't check INS/DEL/UPD permissions. */ -// foreach(rtcell, plan->rtable) -// { -// rte = (RangeTblEntry *)lfirst(rtcell); -// if (rte->rtekind == RTE_RELATION && -// 0 != (rte->requiredPerms & removeperms)) -// rte->requiredPerms &= ~removeperms; -// } -// } -// } - if (log_statement != LOGSTMT_NONE) { /* From b772eb9e2fedadebccafbcfa5ed3f1a195b556d9 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Wed, 17 Jun 2026 16:25:23 +0800 Subject: [PATCH 07/12] Remove MERGE16_FIXME comment in extract_directory The forceoverwrite check is unnecessary here because verify_dir_is_empty_or_create already handles non-empty directories before tar extraction begins. --- src/bin/pg_basebackup/bbstreamer_file.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/pg_basebackup/bbstreamer_file.c b/src/bin/pg_basebackup/bbstreamer_file.c index 504225f0959..6101cc2ab97 100644 --- a/src/bin/pg_basebackup/bbstreamer_file.c +++ b/src/bin/pg_basebackup/bbstreamer_file.c @@ -327,7 +327,6 @@ should_allow_existing_directory(const char *pathname) static void extract_directory(const char *filename, mode_t mode) { - /* MERGE16_FIXME: We should test forceoverwrite here ? */ if (pg_check_dir(filename) != 0) { /* From 778307833137531c8a2a694b8f6a6a98517c1561 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 22 Jun 2026 10:13:59 +0800 Subject: [PATCH 08/12] Fix singlenode prevent_ao_wal test: enable pg_waldump and fix expected output Enable pg_waldump validation in singlenode prevent_ao_wal test (was disabled by MERGE16_FIXME). Broaden matchignore to handle both "fatal" and "error" messages from pg_waldump. Add missing blank lines in expected output after pg_waldump command output. --- .../expected/prevent_ao_wal.out | 47 +++++++++---------- .../sql/prevent_ao_wal.sql | 7 +-- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/test/singlenode_isolation2/expected/prevent_ao_wal.out b/src/test/singlenode_isolation2/expected/prevent_ao_wal.out index fb5f556ce91..be069bcee39 100644 --- a/src/test/singlenode_isolation2/expected/prevent_ao_wal.out +++ b/src/test/singlenode_isolation2/expected/prevent_ao_wal.out @@ -15,7 +15,7 @@ GP_IGNORE: formatted by atmsort.pm -- start_matchignore --- m/pg_waldump: fatal: error in WAL record at */ +-- m/pg_waldump: (fatal|error): .*/ -- m/.*The 'DISTRIBUTED BY' clause determines the distribution of data*/ -- m/.*Table doesn't have 'DISTRIBUTED BY' clause*/ -- end_matchignore @@ -64,31 +64,28 @@ VACUUM -1Uq: ... -- Validate wal records --- MERGE16_FIXME: this should throw a 'pg_waldump: error: error in WAL record at 0/40247EF8: invalid record length at 0/40247F28: expected at least 24, got 0' ERROR, fix it later --- start_ignore ! last_wal_file=$(psql -At -c "SELECT pg_walfile_name(pg_current_wal_lsn())" postgres) && pg_waldump ${last_wal_file} -p ${COORDINATOR_DATA_DIRECTORY}/pg_wal -r appendonly; -rmgr: Appendonly len (rec/tot): 186/ 186, tx: 12661, lsn: 0/F8000178, prev 0/F8000128, desc: APPENDONLY_INSERT insert: rel 1663/221728/180472 seg/offset:0/0 len:136 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12662, lsn: 0/F8000400, prev 0/F80003C0, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:128/0 len:0 -rmgr: Appendonly len (rec/tot): 130/ 130, tx: 12662, lsn: 0/F8000490, prev 0/F8000440, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:0/0 len:80 -rmgr: Appendonly len (rec/tot): 130/ 130, tx: 12662, lsn: 0/F8000520, prev 0/F8000490, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:128/0 len:80 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8000840, prev 0/F8000810, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180472 seg/offset:0/136 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12664, lsn: 0/F8000A18, prev 0/F80009D8, desc: APPENDONLY_INSERT insert: rel 1663/221728/180472 seg/offset:1/0 len:0 -rmgr: Appendonly len (rec/tot): 138/ 138, tx: 12664, lsn: 0/F8000B38, prev 0/F8000AF8, desc: APPENDONLY_INSERT insert: rel 1663/221728/180472 seg/offset:1/0 len:88 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12665, lsn: 0/F8000C98, prev 0/F8000C68, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180472 seg/offset:0/0 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F80412F8, prev 0/F80412C8, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:0/80 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8041338, prev 0/F80412F8, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:128/80 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8307118, prev 0/F83070E8, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180472 seg/offset:1/88 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8307150, prev 0/F8307118, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180472 seg/offset:0/0 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8307208, prev 0/F83071D8, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:0/80 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 0, lsn: 0/F8307248, prev 0/F8307208, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:128/80 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12673, lsn: 0/F8307440, prev 0/F8307400, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:1/0 len:0 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12673, lsn: 0/F8307480, prev 0/F8307440, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:129/0 len:0 -rmgr: Appendonly len (rec/tot): 114/ 114, tx: 12673, lsn: 0/F83075A0, prev 0/F8307560, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:1/0 len:64 -rmgr: Appendonly len (rec/tot): 114/ 114, tx: 12673, lsn: 0/F8307620, prev 0/F83075A0, desc: APPENDONLY_INSERT insert: rel 1663/221728/180476 seg/offset:129/0 len:64 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12674, lsn: 0/F8307780, prev 0/F8307750, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:0/0 -rmgr: Appendonly len (rec/tot): 50/ 50, tx: 12674, lsn: 0/F83077C0, prev 0/F8307780, desc: APPENDONLY_TRUNCATE truncate: rel 1663/221728/180476 seg/offset:128/0 +rmgr: Appendonly len (rec/tot): 186/ 186, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:0/0 len:136 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:128/0 len:0 +rmgr: Appendonly len (rec/tot): 130/ 130, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:0/0 len:80 +rmgr: Appendonly len (rec/tot): 130/ 130, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:128/0 len:80 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/136 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:1/0 len:0 +rmgr: Appendonly len (rec/tot): 138/ 138, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:1/0 len:88 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/0 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/80 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:128/80 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:1/88 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/0 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/80 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:128/80 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:1/0 len:0 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:129/0 len:0 +rmgr: Appendonly len (rec/tot): 114/ 114, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:1/0 len:64 +rmgr: Appendonly len (rec/tot): 114/ 114, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_INSERT insert: rel ####/######/###### seg/offset:129/0 len:64 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:0/0 +rmgr: Appendonly len (rec/tot): 50/ 50, tx: ##, lsn: #/########, prev #/########, desc: APPENDONLY_TRUNCATE truncate: rel ####/######/###### seg/offset:128/0 --- end_ignore -- *********** Set wal_level=minimal ************** !\retcode gpconfig -c wal_level -v minimal --masteronly; @@ -124,10 +121,8 @@ DELETE 5 VACUUM -- Validate wal records --- start_ignore ! last_wal_file=$(psql -At -c "SELECT pg_walfile_name(pg_current_wal_lsn())" postgres) && pg_waldump ${last_wal_file} -p ${COORDINATOR_DATA_DIRECTORY}/pg_wal -r appendonly; --- end_ignore -1U: DROP TABLE ao_foo; DROP diff --git a/src/test/singlenode_isolation2/sql/prevent_ao_wal.sql b/src/test/singlenode_isolation2/sql/prevent_ao_wal.sql index 06b64591658..c9a32051f18 100644 --- a/src/test/singlenode_isolation2/sql/prevent_ao_wal.sql +++ b/src/test/singlenode_isolation2/sql/prevent_ao_wal.sql @@ -14,7 +14,7 @@ -- validate WAL records on the coordinator. -- start_matchignore --- m/pg_waldump: fatal: error in WAL record at */ +-- m/pg_waldump: (fatal|error): .*/ -- m/.*The 'DISTRIBUTED BY' clause determines the distribution of data*/ -- m/.*Table doesn't have 'DISTRIBUTED BY' clause*/ -- end_matchignore @@ -49,10 +49,7 @@ -1Uq: -- Validate wal records --- MERGE16_FIXME: this should throw a 'pg_waldump: error: error in WAL record at 0/40247EF8: invalid record length at 0/40247F28: expected at least 24, got 0' ERROR, fix it later --- start_ignore ! last_wal_file=$(psql -At -c "SELECT pg_walfile_name(pg_current_wal_lsn())" postgres) && pg_waldump ${last_wal_file} -p ${COORDINATOR_DATA_DIRECTORY}/pg_wal -r appendonly; --- end_ignore -- *********** Set wal_level=minimal ************** !\retcode gpconfig -c wal_level -v minimal --masteronly; @@ -75,9 +72,7 @@ -1U: VACUUM; -- Validate wal records --- start_ignore ! last_wal_file=$(psql -At -c "SELECT pg_walfile_name(pg_current_wal_lsn())" postgres) && pg_waldump ${last_wal_file} -p ${COORDINATOR_DATA_DIRECTORY}/pg_wal -r appendonly; --- end_ignore -1U: DROP TABLE ao_foo; -1U: DROP TABLE aoco_foo; From bd49e97f615301351ed2b66bac96b0029377de22 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 22 Jun 2026 10:14:07 +0800 Subject: [PATCH 09/12] Re-enable select_throttle and workfile_mgr_test in singlenode Re-enable segwalrep/select_throttle in isolation2_schedule and workfile_mgr_test in singlenode. Fix gpstop -ari to -arf for singlenode mode where immediate shutdown causes crash recovery and blocks connections. --- src/test/isolation2/isolation2_schedule | 3 +-- src/test/singlenode_isolation2/input/workfile_mgr_test.source | 4 ++-- src/test/singlenode_isolation2/isolation2_schedule | 3 +-- .../singlenode_isolation2/output/workfile_mgr_test.source | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/test/isolation2/isolation2_schedule b/src/test/isolation2/isolation2_schedule index 7e7e4220d12..82d23731fb6 100644 --- a/src/test/isolation2/isolation2_schedule +++ b/src/test/isolation2/isolation2_schedule @@ -253,8 +253,7 @@ test: segwalrep/dtm_recovery_on_standby test: segwalrep/commit_blocking_on_standby test: segwalrep/dtx_recovery_wait_lsn -# MERGE16_FIXME: enable this case latter -# test: segwalrep/select_throttle +test: segwalrep/select_throttle test: segwalrep/startup_rename_prepared_xlog test: fts_manual_probe test: fts_session_reset diff --git a/src/test/singlenode_isolation2/input/workfile_mgr_test.source b/src/test/singlenode_isolation2/input/workfile_mgr_test.source index 30f03315d7e..f5e189e694b 100644 --- a/src/test/singlenode_isolation2/input/workfile_mgr_test.source +++ b/src/test/singlenode_isolation2/input/workfile_mgr_test.source @@ -57,7 +57,7 @@ language plpgsql volatile execute on all segments; -- start_ignore !\retcode gpconfig -c gp_workfile_max_entries -v 32 --skipvalidation; -!\retcode gpstop -ari; +!\retcode gpstop -arf; -- end_ignore -- setup for workfile made in temp tablespace test @@ -80,7 +80,7 @@ language plpgsql volatile execute on all segments; -- start_ignore !\retcode gpconfig -r gp_workfile_max_entries --skipvalidation; -!\retcode gpstop -ari; +!\retcode gpstop -arf; -- end_ignore -- test workset cleanup diff --git a/src/test/singlenode_isolation2/isolation2_schedule b/src/test/singlenode_isolation2/isolation2_schedule index adf4e6c0ede..7e5266d1c84 100644 --- a/src/test/singlenode_isolation2/isolation2_schedule +++ b/src/test/singlenode_isolation2/isolation2_schedule @@ -211,8 +211,7 @@ test: uao/bitmapindex_rescan_column # test: add_column_after_vacuum_skip_drop_column # test: vacuum_after_vacuum_skip_drop_column # test workfile_mgr -# MERGE16_FIXME: enable workfile_mgr_test later -#test: workfile_mgr_test +test: workfile_mgr_test # test: pg_basebackup # test: pg_basebackup_with_tablespaces test: enable_autovacuum diff --git a/src/test/singlenode_isolation2/output/workfile_mgr_test.source b/src/test/singlenode_isolation2/output/workfile_mgr_test.source index a6821ecc38b..5fcbd06dde4 100644 --- a/src/test/singlenode_isolation2/output/workfile_mgr_test.source +++ b/src/test/singlenode_isolation2/output/workfile_mgr_test.source @@ -30,7 +30,7 @@ CREATE -- end_ignore (exited with code 0) -!\retcode gpstop -ari; +!\retcode gpstop -arf; -- start_ignore 20200923:12:05:57:014232 gpstop:mdw:gpadmin-[INFO]:-Starting gpstop with args: -ari 20200923:12:05:57:014232 gpstop:mdw:gpadmin-[INFO]:-Gathering information and validating the environment... @@ -122,7 +122,7 @@ DROP -- end_ignore (exited with code 0) -!\retcode gpstop -ari; +!\retcode gpstop -arf; -- start_ignore 20230630:09:01:15:025313 gpstop:merge:gpadmin-[INFO]:-Starting gpstop with args: -ari 20230630:09:01:15:025313 gpstop:merge:gpadmin-[INFO]:-Gathering information and validating the environment... From ff3e762924a2eebb13052ca55f8ff620a8308c17 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Thu, 18 Jun 2026 11:16:59 +0800 Subject: [PATCH 10/12] Fix flaky resgroup_cpu_max_percent: average all CPU samples verify_cpu_usage() only used the first sample (all_info[0]) instead of averaging all collected samples, making it sensitive to single-sample fluctuations on busy CI machines. Use the mean of all samples as the function comment originally intended. --- .../isolation2/expected/resgroup/resgroup_cpu_max_percent.out | 4 ++-- .../test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql | 3 +-- .../isolation2/expected/resgroup/resgroup_cpu_max_percent.out | 4 ++-- src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql | 3 +-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contrib/pax_storage/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out b/contrib/pax_storage/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out index ae21059fcb6..1e011ecec22 100644 --- a/contrib/pax_storage/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out +++ b/contrib/pax_storage/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out @@ -33,8 +33,8 @@ CREATE -- verify_cpu_usage: calculate each QE's average cpu usage using all the data in -- the table cpu_usage_sample. And compare the average value to the expected value. -- return true if the practical value is close to the expected value. -CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json import functools -all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) usage = float(all_info[0]['cpu']) +CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json +all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) usage = sum(float(row['cpu']) for row in all_info) / len(all_info) return abs(usage - expect_cpu_usage) <= err_rate $$ LANGUAGE plpython3u; CREATE diff --git a/contrib/pax_storage/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql b/contrib/pax_storage/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql index 14220c38a42..a014108bb52 100644 --- a/contrib/pax_storage/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql +++ b/contrib/pax_storage/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql @@ -38,12 +38,11 @@ $$ LANGUAGE plpython3u; CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json - import functools all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) - usage = float(all_info[0]['cpu']) + usage = sum(float(row['cpu']) for row in all_info) / len(all_info) return abs(usage - expect_cpu_usage) <= err_rate $$ LANGUAGE plpython3u; diff --git a/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out b/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out index 2e7b32f1d74..44969ba7eea 100644 --- a/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out +++ b/src/test/isolation2/expected/resgroup/resgroup_cpu_max_percent.out @@ -33,8 +33,8 @@ CREATE -- verify_cpu_usage: calculate each QE's average cpu usage using all the data in -- the table cpu_usage_sample. And compare the average value to the expected value. -- return true if the practical value is close to the expected value. -CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json import functools -all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) usage = float(all_info[0]['cpu']) +CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json +all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) usage = sum(float(row['cpu']) for row in all_info) / len(all_info) return abs(usage - expect_cpu_usage) <= err_rate $$ LANGUAGE plpython3u; CREATE diff --git a/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql b/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql index c7dfc9f60b0..89fa523cc88 100644 --- a/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql +++ b/src/test/isolation2/sql/resgroup/resgroup_cpu_max_percent.sql @@ -38,12 +38,11 @@ $$ LANGUAGE plpython3u; CREATE OR REPLACE FUNCTION verify_cpu_usage(groupname TEXT, expect_cpu_usage INT, err_rate INT) RETURNS BOOL AS $$ import json - import functools all_info = plpy.execute(''' SELECT sample::json->'{name}' AS cpu FROM cpu_usage_samples '''.format(name=groupname)) - usage = float(all_info[0]['cpu']) + usage = sum(float(row['cpu']) for row in all_info) / len(all_info) return abs(usage - expect_cpu_usage) <= err_rate $$ LANGUAGE plpython3u; From e1e11c5f71da22dd76c39e74f3d32f3ee2122e68 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Mon, 22 Jun 2026 18:15:02 +0800 Subject: [PATCH 11/12] Fix rowtypes MERGE16_FIXME: use complex_t and fix record_in tupdesc double-release Cloudberry has a built-in scalar 'complex' type whose complex_in doesn't support PG16's soft-error API. Rename to 'complex_t' composite type in rowtypes tests to avoid conflict. Fix record_in double ReleaseTupleDesc bug: remove 6 redundant ReleaseTupleDesc calls before 'goto fail', since the fail label already releases tupdesc. The double-release caused SIGSEGV on malformed composite type input via pg_input_is_valid. --- .../src/test/regress/expected/rowtypes.out | 15 +++++---------- .../test/regress/expected/rowtypes_optimizer.out | 15 +++++---------- .../pax_storage/src/test/regress/sql/rowtypes.sql | 15 +++++---------- src/backend/utils/adt/rowtypes.c | 6 ------ src/test/regress/expected/rowtypes.out | 15 +++++---------- src/test/regress/expected/rowtypes_optimizer.out | 15 +++++---------- src/test/regress/sql/rowtypes.sql | 15 +++++---------- 7 files changed, 30 insertions(+), 66 deletions(-) diff --git a/contrib/pax_storage/src/test/regress/expected/rowtypes.out b/contrib/pax_storage/src/test/regress/expected/rowtypes.out index 9c92b2c403d..076f5cbb606 100644 --- a/contrib/pax_storage/src/test/regress/expected/rowtypes.out +++ b/contrib/pax_storage/src/test/regress/expected/rowtypes.out @@ -70,41 +70,36 @@ LINE 1: select '(Joe,Blow) /'::fullname; ^ DETAIL: Junk after right parenthesis. -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); +SELECT pg_input_is_valid('(1,2)', 'complex_t'); pg_input_is_valid ------------------- t (1 row) -SELECT pg_input_is_valid('(1,2', 'complex'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT pg_input_is_valid('(1,zed)', 'complex'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); message | detail | hint | sql_error_code -------------------------------------------------------+--------+------+---------------- invalid input syntax for type double precision: "zed" | | | 22P02 (1 row) -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); message | detail | hint | sql_error_code ---------------------------------------------------+--------+------+---------------- "1e400" is out of range for type double precision | | | 22003 (1 row) --- end_ignore create temp table quadtable(f1 int, q quad); insert into quadtable values (1, ((3.3,4.4),(5.5,6.6))); insert into quadtable values (2, ((null,4.4),(5.5,6.6))); diff --git a/contrib/pax_storage/src/test/regress/expected/rowtypes_optimizer.out b/contrib/pax_storage/src/test/regress/expected/rowtypes_optimizer.out index 32d93a68e4d..f0a84ed44d4 100644 --- a/contrib/pax_storage/src/test/regress/expected/rowtypes_optimizer.out +++ b/contrib/pax_storage/src/test/regress/expected/rowtypes_optimizer.out @@ -70,41 +70,36 @@ LINE 1: select '(Joe,Blow) /'::fullname; ^ DETAIL: Junk after right parenthesis. -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); +SELECT pg_input_is_valid('(1,2)', 'complex_t'); pg_input_is_valid ------------------- t (1 row) -SELECT pg_input_is_valid('(1,2', 'complex'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT pg_input_is_valid('(1,zed)', 'complex'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); message | detail | hint | sql_error_code -------------------------------------------------------+--------+------+---------------- invalid input syntax for type double precision: "zed" | | | 22P02 (1 row) -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); message | detail | hint | sql_error_code ---------------------------------------------------+--------+------+---------------- "1e400" is out of range for type double precision | | | 22003 (1 row) --- end_ignore create temp table quadtable(f1 int, q quad); insert into quadtable values (1, ((3.3,4.4),(5.5,6.6))); insert into quadtable values (2, ((null,4.4),(5.5,6.6))); diff --git a/contrib/pax_storage/src/test/regress/sql/rowtypes.sql b/contrib/pax_storage/src/test/regress/sql/rowtypes.sql index 7db4925dbe8..93319bf7e81 100644 --- a/contrib/pax_storage/src/test/regress/sql/rowtypes.sql +++ b/contrib/pax_storage/src/test/regress/sql/rowtypes.sql @@ -42,16 +42,11 @@ select ' (Joe,Blow) '::fullname; -- ok, extra whitespace select '(Joe,Blow) /'::fullname; -- bad -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); -SELECT pg_input_is_valid('(1,2', 'complex'); -SELECT pg_input_is_valid('(1,zed)', 'complex'); -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); --- end_ignore +SELECT pg_input_is_valid('(1,2)', 'complex_t'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); create temp table quadtable(f1 int, q quad); diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 3250d285e02..f0fa5838e66 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -154,7 +154,6 @@ record_in(PG_FUNCTION_ARGS) ptr++; if (*ptr++ != '(') { - ReleaseTupleDesc(tupdesc); errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed record literal: \"%s\"", string), @@ -186,7 +185,6 @@ record_in(PG_FUNCTION_ARGS) ptr++; else { - ReleaseTupleDesc(tupdesc); /* *ptr must be ')' */ errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -214,7 +212,6 @@ record_in(PG_FUNCTION_ARGS) if (ch == '\0') { - ReleaseTupleDesc(tupdesc); errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed record literal: \"%s\"", @@ -226,7 +223,6 @@ record_in(PG_FUNCTION_ARGS) { if (*ptr == '\0') { - ReleaseTupleDesc(tupdesc); errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed record literal: \"%s\"", @@ -285,7 +281,6 @@ record_in(PG_FUNCTION_ARGS) if (*ptr++ != ')') { - ReleaseTupleDesc(tupdesc); errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed record literal: \"%s\"", string), @@ -297,7 +292,6 @@ record_in(PG_FUNCTION_ARGS) ptr++; if (*ptr) { - ReleaseTupleDesc(tupdesc); errsave(escontext, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed record literal: \"%s\"", string), diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index ecd4ee0deb3..d86bab812db 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -70,41 +70,36 @@ LINE 1: select '(Joe,Blow) /'::fullname; ^ DETAIL: Junk after right parenthesis. -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); +SELECT pg_input_is_valid('(1,2)', 'complex_t'); pg_input_is_valid ------------------- t (1 row) -SELECT pg_input_is_valid('(1,2', 'complex'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT pg_input_is_valid('(1,zed)', 'complex'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); message | detail | hint | sql_error_code -------------------------------------------------------+--------+------+---------------- invalid input syntax for type double precision: "zed" | | | 22P02 (1 row) -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); message | detail | hint | sql_error_code ---------------------------------------------------+--------+------+---------------- "1e400" is out of range for type double precision | | | 22003 (1 row) --- end_ignore create temp table quadtable(f1 int, q quad); insert into quadtable values (1, ((3.3,4.4),(5.5,6.6))); insert into quadtable values (2, ((null,4.4),(5.5,6.6))); diff --git a/src/test/regress/expected/rowtypes_optimizer.out b/src/test/regress/expected/rowtypes_optimizer.out index e937a160d96..6edc5cbda2a 100644 --- a/src/test/regress/expected/rowtypes_optimizer.out +++ b/src/test/regress/expected/rowtypes_optimizer.out @@ -70,41 +70,36 @@ LINE 1: select '(Joe,Blow) /'::fullname; ^ DETAIL: Junk after right parenthesis. -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); +SELECT pg_input_is_valid('(1,2)', 'complex_t'); pg_input_is_valid ------------------- t (1 row) -SELECT pg_input_is_valid('(1,2', 'complex'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT pg_input_is_valid('(1,zed)', 'complex'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); pg_input_is_valid ------------------- f (1 row) -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); message | detail | hint | sql_error_code -------------------------------------------------------+--------+------+---------------- invalid input syntax for type double precision: "zed" | | | 22P02 (1 row) -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); message | detail | hint | sql_error_code ---------------------------------------------------+--------+------+---------------- "1e400" is out of range for type double precision | | | 22003 (1 row) --- end_ignore create temp table quadtable(f1 int, q quad); insert into quadtable values (1, ((3.3,4.4),(5.5,6.6))); insert into quadtable values (2, ((null,4.4),(5.5,6.6))); diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index 8175022c3f4..655fe4c0349 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -42,16 +42,11 @@ select ' (Joe,Blow) '::fullname; -- ok, extra whitespace select '(Joe,Blow) /'::fullname; -- bad -- test non-error-throwing API --- MERGE16_FIXME: --- The greenplum implement complex type by itself, postgres implement --- it now. should we use the complex type implemented by postgres. --- start_ignore -SELECT pg_input_is_valid('(1,2)', 'complex'); -SELECT pg_input_is_valid('(1,2', 'complex'); -SELECT pg_input_is_valid('(1,zed)', 'complex'); -SELECT * FROM pg_input_error_info('(1,zed)', 'complex'); -SELECT * FROM pg_input_error_info('(1,1e400)', 'complex'); --- end_ignore +SELECT pg_input_is_valid('(1,2)', 'complex_t'); +SELECT pg_input_is_valid('(1,2', 'complex_t'); +SELECT pg_input_is_valid('(1,zed)', 'complex_t'); +SELECT * FROM pg_input_error_info('(1,zed)', 'complex_t'); +SELECT * FROM pg_input_error_info('(1,1e400)', 'complex_t'); create temp table quadtable(f1 int, q quad); From 044fcbe8d1a4d05482863eb133a674a655f9dbc3 Mon Sep 17 00:00:00 2001 From: liushengsong Date: Tue, 23 Jun 2026 10:34:36 +0800 Subject: [PATCH 12/12] Fix flaky vacuum_progress_column/row: remove inline DDL and wait_for_mirror_down Remove inline CREATE OR REPLACE FUNCTION wait_for_mirror_down and its SELECT calls from vacuum_progress tests. The DDL dispatch to segments created distributed transactions that advanced DistributedLogShared-> oldestXmin past compact XIDs, causing the new vacuum worker in post-cleanup to see stale segments as recyclable (heap_blks_vacuumed=9, index_vacuum_count=2 instead of 0/0). The wait_for_mirror_down function is already defined in setup.sql, so the inline definition was redundant and harmful. --- .../expected/vacuum_progress_column.out | 17 ++++--------- .../expected/vacuum_progress_row.out | 16 ------------- .../isolation2/sql/vacuum_progress_column.sql | 21 ---------------- .../isolation2/sql/vacuum_progress_row.sql | 24 ------------------- 4 files changed, 4 insertions(+), 74 deletions(-) diff --git a/src/test/isolation2/expected/vacuum_progress_column.out b/src/test/isolation2/expected/vacuum_progress_column.out index fcc983f1e43..12a3bceb78f 100644 --- a/src/test/isolation2/expected/vacuum_progress_column.out +++ b/src/test/isolation2/expected/vacuum_progress_column.out @@ -339,15 +339,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he -------------------------- Success: (1 row) --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -CREATE OR REPLACE FUNCTION wait_for_mirror_down(content_id int) RETURNS bool AS $$ declare /* in func */ retries int; /* in func */ begin /* in func */ retries := 60; /* in func */ loop /* in func */ perform gp_request_fts_probe_scan(); /* in func */ if (select status = 'd' from gp_segment_configuration where content = content_id and role = 'm') then /* in func */ return true; /* in func */ end if; /* in func */ if retries <= 0 then /* in func */ return false; /* in func */ end if; /* in func */ perform pg_sleep(1); /* in func */ retries := retries - 1; /* in func */ end loop; /* in func */ end; /* in func */ $$ language plpgsql; -CREATE -2: SELECT wait_for_mirror_down(1); - wait_for_mirror_down ----------------------- - t -(1 row) -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point @@ -398,14 +389,14 @@ CREATE select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; gp_segment_id | relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ---------------+---------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - 2 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 9 | 2 | 0 | 0 - 0 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 9 | 2 | 0 | 0 - 1 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 9 | 2 | 0 | 0 + 2 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 0 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 1 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 (3 rows) select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ---------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 27 | 6 | 0 | 0 + vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 (1 row) 2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; diff --git a/src/test/isolation2/expected/vacuum_progress_row.out b/src/test/isolation2/expected/vacuum_progress_row.out index 29809709eab..ef39d8edaf3 100644 --- a/src/test/isolation2/expected/vacuum_progress_row.out +++ b/src/test/isolation2/expected/vacuum_progress_row.out @@ -293,8 +293,6 @@ SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuu -- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case -- in which vacuum worker isn't changed. -CREATE OR REPLACE FUNCTION wait_for_mirror_down(content_id int) RETURNS bool AS $$ declare /* in func */ retries int; /* in func */ begin /* in func */ retries := 60; /* in func */ loop /* in func */ perform gp_request_fts_probe_scan(); /* in func */ if (select status = 'd' from gp_segment_configuration where content = content_id and role = 'm') then /* in func */ return true; /* in func */ end if; /* in func */ if retries <= 0 then /* in func */ return false; /* in func */ end if; /* in func */ perform pg_sleep(1); /* in func */ retries := retries - 1; /* in func */ end loop; /* in func */ end; /* in func */ $$ language plpgsql; -CREATE DROP TABLE IF EXISTS vacuum_progress_ao_row; DROP CREATE TABLE vacuum_progress_ao_row(i int, j int); @@ -395,13 +393,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he -------------------------- Success: (1 row) --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -2: SELECT wait_for_mirror_down(1); - wait_for_mirror_down ----------------------- - t -(1 row) -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point @@ -606,13 +597,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he -------------------------- Success: (1 row) --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -2: SELECT wait_for_mirror_down(1); - wait_for_mirror_down ----------------------- - t -(1 row) -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point diff --git a/src/test/isolation2/sql/vacuum_progress_column.sql b/src/test/isolation2/sql/vacuum_progress_column.sql index 519c3e37200..60250368b46 100644 --- a/src/test/isolation2/sql/vacuum_progress_column.sql +++ b/src/test/isolation2/sql/vacuum_progress_column.sql @@ -141,27 +141,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he 2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- resume walsender and let it exit so that mirror stop can be detected 2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -CREATE OR REPLACE FUNCTION wait_for_mirror_down(content_id int) RETURNS bool AS $$ -declare /* in func */ - retries int; /* in func */ -begin /* in func */ - retries := 60; /* in func */ - loop /* in func */ - perform gp_request_fts_probe_scan(); /* in func */ - if (select status = 'd' from gp_segment_configuration where content = content_id and role = 'm') then /* in func */ - return true; /* in func */ - end if; /* in func */ - if retries <= 0 then /* in func */ - return false; /* in func */ - end if; /* in func */ - perform pg_sleep(1); /* in func */ - retries := retries - 1; /* in func */ - end loop; /* in func */ -end; /* in func */ -$$ language plpgsql; -2: SELECT wait_for_mirror_down(1); -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point diff --git a/src/test/isolation2/sql/vacuum_progress_row.sql b/src/test/isolation2/sql/vacuum_progress_row.sql index 125368df72b..c832a1fd0df 100644 --- a/src/test/isolation2/sql/vacuum_progress_row.sql +++ b/src/test/isolation2/sql/vacuum_progress_row.sql @@ -107,24 +107,6 @@ SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuu -- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case -- in which vacuum worker isn't changed. -CREATE OR REPLACE FUNCTION wait_for_mirror_down(content_id int) RETURNS bool AS $$ -declare /* in func */ - retries int; /* in func */ -begin /* in func */ - retries := 60; /* in func */ - loop /* in func */ - perform gp_request_fts_probe_scan(); /* in func */ - if (select status = 'd' from gp_segment_configuration where content = content_id and role = 'm') then /* in func */ - return true; /* in func */ - end if; /* in func */ - if retries <= 0 then /* in func */ - return false; /* in func */ - end if; /* in func */ - perform pg_sleep(1); /* in func */ - retries := retries - 1; /* in func */ - end loop; /* in func */ -end; /* in func */ -$$ language plpgsql; DROP TABLE IF EXISTS vacuum_progress_ao_row; CREATE TABLE vacuum_progress_ao_row(i int, j int); CREATE INDEX on vacuum_progress_ao_row(i); @@ -164,9 +146,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he 2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- resume walsender and let it exit so that mirror stop can be detected 2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -2: SELECT wait_for_mirror_down(1); -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point @@ -241,9 +220,6 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he 2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- resume walsender and let it exit so that mirror stop can be detected 2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; --- Trigger FTS probe repeatedly until mirror is marked as down, so that --- FTS version change propagates to QD and gang gets reset. -2: SELECT wait_for_mirror_down(1); -- Ensure we enter into the target logic which stops cumulative data but -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point