diff --git a/src/common/backend/utils/cache/partcache.cpp b/src/common/backend/utils/cache/partcache.cpp index 3e9c5895b..c0026ac25 100644 --- a/src/common/backend/utils/cache/partcache.cpp +++ b/src/common/backend/utils/cache/partcache.cpp @@ -1827,6 +1827,28 @@ bool PartitionInvisibleMetadataKeep(Datum datumRelOptions) return ret; } +/* Check whether a partition is properly used. */ +bool PartitionParentOidIsLive(Datum parentDatum) +{ + Oid parentid = InvalidOid; + HeapTuple partTuple = NULL; + + if (!PointerIsValid(parentDatum)) { + return false; + } + + parentid = DatumGetObjectId(parentDatum); + + /* Get table information from syscache */ + partTuple = SearchSysCache1WithLogLevel(RELOID, ObjectIdGetDatum(parentid), LOG); + if (HeapTupleIsValid(partTuple)) { + ReleaseSysCache(partTuple); + return true; + } + + return false; +} + /* * In pg_partition, search all tuples (visible and invisible) containing wait_clean_gpi=y * in reloptios of one partitioed relation and set wait_clean_gpi=n diff --git a/src/gausskernel/optimizer/commands/vacuumlazy.cpp b/src/gausskernel/optimizer/commands/vacuumlazy.cpp index 844ec7d73..7b5f4bab5 100644 --- a/src/gausskernel/optimizer/commands/vacuumlazy.cpp +++ b/src/gausskernel/optimizer/commands/vacuumlazy.cpp @@ -113,6 +113,7 @@ typedef struct LVRelStats { double* new_idx_tuples; bool* idx_estimated; Oid currVacuumPartOid; /* current lazy vacuum partition oid */ + bool hasKeepInvisbleTuples; } LVRelStats; typedef struct ValPrefetchList { @@ -396,6 +397,7 @@ void lazy_vacuum_rel(Relation onerel, VacuumStmt* vacstmt, BufferAccessStrategy vacrelstats->num_index_scans = 0; vacrelstats->pages_removed = 0; vacrelstats->lock_waiter_detected = false; + vacrelstats->hasKeepInvisbleTuples = false; /* Open all indexes of the relation */ if (RelationIsPartition(onerel)) { @@ -445,8 +447,9 @@ void lazy_vacuum_rel(Relation onerel, VacuumStmt* vacstmt, BufferAccessStrategy new_rel_allvisible = new_rel_pages; new_frozen_xid = u_sess->cmd_cxt.FreezeLimit; - if (vacrelstats->scanned_pages < vacrelstats->rel_pages) + if (vacrelstats->scanned_pages < vacrelstats->rel_pages || vacrelstats->hasKeepInvisbleTuples) { new_frozen_xid = InvalidTransactionId; + } if (RelationIsPartition(onerel)) { Assert(vacstmt->onepart != NULL); @@ -898,6 +901,7 @@ static IndexBulkDeleteResult** lazy_scan_heap( OffsetNumber offnum, maxoff; bool tupgone = false; bool hastup = false; + bool keepThisInvisbleTuple = false; int prev_dead_count; OffsetNumber frozen[MaxOffsetNumber]; int nfrozen; @@ -1165,6 +1169,7 @@ static IndexBulkDeleteResult** lazy_scan_heap( tuple.t_bucketId = RelationGetBktid(onerel); HeapTupleCopyBaseFromPage(&tuple, page); tupgone = false; + keepThisInvisbleTuple = false; if (u_sess->attr.attr_storage.enable_debug_vacuum) t_thrd.utils_cxt.pRelatedRel = onerel; @@ -1187,11 +1192,12 @@ static IndexBulkDeleteResult** lazy_scan_heap( * cheaper to get rid of it in the next pruning pass than * to treat it like an indexed tuple. */ - if (HeapTupleIsHotUpdated(&tuple) || HeapTupleIsHeapOnly(&tuple) || - HeapKeepInvisbleTuple(&tuple, RelationGetDescr(onerel))) + keepThisInvisbleTuple = HeapKeepInvisbleTuple(&tuple, RelationGetDescr(onerel)); + if (HeapTupleIsHotUpdated(&tuple) || HeapTupleIsHeapOnly(&tuple) || keepThisInvisbleTuple) { nkeep += 1; - else + } else { tupgone = true; /* we can delete the tuple */ + } all_visible = false; break; case HEAPTUPLE_LIVE: @@ -1265,6 +1271,8 @@ static IndexBulkDeleteResult** lazy_scan_heap( tups_vacuumed += 1; has_dead_tuples = true; + } else if (keepThisInvisbleTuple) { + vacrelstats->hasKeepInvisbleTuples = true; } else { num_tuples += 1; hastup = true; diff --git a/src/gausskernel/storage/access/common/heaptuple.cpp b/src/gausskernel/storage/access/common/heaptuple.cpp index 0e0b9c169..b4e305d3f 100644 --- a/src/gausskernel/storage/access/common/heaptuple.cpp +++ b/src/gausskernel/storage/access/common/heaptuple.cpp @@ -3232,13 +3232,15 @@ void heap_slot_store_heap_tuple(HeapTuple tuple, TupleTableSlot* slot, Buffer bu bool HeapKeepInvisbleTuple(HeapTuple tuple, TupleDesc tupleDesc, KeepInvisbleTupleFunc checkKeepFunc) { static KeepInvisbleOpt keepInvisibleArray[] = { - {PartitionRelationId, Anum_pg_partition_reloptions, PartitionInvisibleMetadataKeep}}; + {PartitionRelationId, Anum_pg_partition_reloptions, PartitionInvisibleMetadataKeep}, + {PartitionRelationId, Anum_pg_partition_parentid, PartitionParentOidIsLive}}; + bool ret = true; for (int i = 0; i < (int)lengthof(keepInvisibleArray); i++) { bool isNull = false; KeepInvisbleOpt keepOpt = keepInvisibleArray[i]; - if (keepOpt.tableOid != tuple->t_tableOid) { + if (keepOpt.tableOid != tuple->t_tableOid || !ret) { return false; } @@ -3248,13 +3250,13 @@ bool HeapKeepInvisbleTuple(HeapTuple tuple, TupleDesc tupleDesc, KeepInvisbleTup } if (checkKeepFunc != NULL) { - return checkKeepFunc(checkDatum); + ret &= checkKeepFunc(checkDatum); } else if (keepOpt.checkKeepFunc != NULL) { - return keepOpt.checkKeepFunc(checkDatum); + ret &= keepOpt.checkKeepFunc(checkDatum); } else { return false; } } - return false; + return ret; } diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h index d41c3cb9a..8f1b5d18d 100644 --- a/src/include/utils/partcache.h +++ b/src/include/utils/partcache.h @@ -89,6 +89,7 @@ extern Datum SetWaitCleanGpiRelOptions(Datum oldOptions, bool enable); extern void PartitionedSetWaitCleanGpi(const char* parentName, Oid parentPartOid, bool enable, bool inplace); extern void PartitionSetWaitCleanGpi(Oid partOid, bool enable, bool inplace); extern bool PartitionInvisibleMetadataKeep(Datum datumRelOptions); +extern bool PartitionParentOidIsLive(Datum parentDatum); extern void PartitionedSetEnabledClean(Oid parentOid); extern void PartitionSetEnabledClean( Oid parentOid, const Bitmapset* cleanedParts, const Bitmapset* invisibleParts, bool updatePartitioned); diff --git a/src/test/regress/expected/gpi_alter_partition.out b/src/test/regress/expected/gpi_alter_partition.out index d895de1ab..567b72eb5 100644 --- a/src/test/regress/expected/gpi_alter_partition.out +++ b/src/test/regress/expected/gpi_alter_partition.out @@ -1232,6 +1232,7 @@ select count(*) from alter_table where INV_WAREHOUSE_SK < 20000; 4000 (1 row) +vacuum freeze pg_partition; --clean drop index if exists local_exchange_table_index1; drop table if exists exchange_table; diff --git a/src/test/regress/sql/gpi_alter_partition.sql b/src/test/regress/sql/gpi_alter_partition.sql index 009e0f599..e70f1ec09 100644 --- a/src/test/regress/sql/gpi_alter_partition.sql +++ b/src/test/regress/sql/gpi_alter_partition.sql @@ -289,6 +289,8 @@ explain (costs off) select count(*) from alter_table where INV_WAREHOUSE_SK < 20 select count(*) from alter_table where INV_WAREHOUSE_SK < 20000; +vacuum freeze pg_partition; + --clean drop index if exists local_exchange_table_index1; drop table if exists exchange_table;