mirror of https://github.com/citusdata/citus.git
Add support for VACUUM/ANALYZE to recurse into inheritance children by default
parent
3399d660f3
commit
990312bf61
|
|
@ -48,21 +48,27 @@ typedef struct CitusVacuumParams
|
|||
#endif
|
||||
} CitusVacuumParams;
|
||||
|
||||
/*
|
||||
* Information we track per VACUUM/ANALYZE target relation.
|
||||
*/
|
||||
typedef struct CitusVacuumRelation
|
||||
{
|
||||
VacuumRelation *vacuumRelation;
|
||||
Oid relationId;
|
||||
} CitusVacuumRelation;
|
||||
|
||||
/* Local functions forward declarations for processing distributed table commands */
|
||||
static bool IsDistributedVacuumStmt(List *vacuumRelationIdList);
|
||||
static bool IsDistributedVacuumStmt(List *vacuumRelationList);
|
||||
static List * VacuumTaskList(Oid relationId, CitusVacuumParams vacuumParams,
|
||||
List *vacuumColumnList);
|
||||
static char * DeparseVacuumStmtPrefix(CitusVacuumParams vacuumParams);
|
||||
static char * DeparseVacuumColumnNames(List *columnNameList);
|
||||
static List * VacuumColumnList(VacuumStmt *vacuumStmt, int relationIndex);
|
||||
static List * ExtractVacuumTargetRels(VacuumStmt *vacuumStmt);
|
||||
static void ExecuteVacuumOnDistributedTables(VacuumStmt *vacuumStmt, List *relationIdList,
|
||||
static void ExecuteVacuumOnDistributedTables(VacuumStmt *vacuumStmt, List *relationList,
|
||||
CitusVacuumParams vacuumParams);
|
||||
static void ExecuteUnqualifiedVacuumTasks(VacuumStmt *vacuumStmt,
|
||||
CitusVacuumParams vacuumParams);
|
||||
static CitusVacuumParams VacuumStmtParams(VacuumStmt *vacstmt);
|
||||
static List * VacuumRelationIdList(VacuumStmt *vacuumStmt, CitusVacuumParams
|
||||
vacuumParams);
|
||||
static List * VacuumRelationList(VacuumStmt *vacuumStmt, CitusVacuumParams vacuumParams);
|
||||
|
||||
/*
|
||||
* PostprocessVacuumStmt processes vacuum statements that may need propagation to
|
||||
|
|
@ -97,7 +103,7 @@ PostprocessVacuumStmt(Node *node, const char *vacuumCommand)
|
|||
* when no table is specified propagate the command as it is;
|
||||
* otherwise, only propagate when there is at least 1 citus table
|
||||
*/
|
||||
List *relationIdList = VacuumRelationIdList(vacuumStmt, vacuumParams);
|
||||
List *vacuumRelationList = VacuumRelationList(vacuumStmt, vacuumParams);
|
||||
|
||||
if (list_length(vacuumStmt->rels) == 0)
|
||||
{
|
||||
|
|
@ -105,11 +111,11 @@ PostprocessVacuumStmt(Node *node, const char *vacuumCommand)
|
|||
|
||||
ExecuteUnqualifiedVacuumTasks(vacuumStmt, vacuumParams);
|
||||
}
|
||||
else if (IsDistributedVacuumStmt(relationIdList))
|
||||
else if (IsDistributedVacuumStmt(vacuumRelationList))
|
||||
{
|
||||
/* there is at least 1 citus table specified */
|
||||
|
||||
ExecuteVacuumOnDistributedTables(vacuumStmt, relationIdList,
|
||||
ExecuteVacuumOnDistributedTables(vacuumStmt, vacuumRelationList,
|
||||
vacuumParams);
|
||||
}
|
||||
|
||||
|
|
@ -120,39 +126,58 @@ PostprocessVacuumStmt(Node *node, const char *vacuumCommand)
|
|||
|
||||
|
||||
/*
|
||||
* VacuumRelationIdList returns the oid of the relations in the given vacuum statement.
|
||||
* VacuumRelationList returns the list of relations in the given vacuum statement,
|
||||
* along with their resolved Oids (if they can be locked).
|
||||
*/
|
||||
static List *
|
||||
VacuumRelationIdList(VacuumStmt *vacuumStmt, CitusVacuumParams vacuumParams)
|
||||
VacuumRelationList(VacuumStmt *vacuumStmt, CitusVacuumParams vacuumParams)
|
||||
{
|
||||
LOCKMODE lockMode = (vacuumParams.options & VACOPT_FULL) ? AccessExclusiveLock :
|
||||
ShareUpdateExclusiveLock;
|
||||
|
||||
bool skipLocked = (vacuumParams.options & VACOPT_SKIP_LOCKED);
|
||||
|
||||
List *vacuumRelationList = ExtractVacuumTargetRels(vacuumStmt);
|
||||
List *relationList = NIL;
|
||||
|
||||
List *relationIdList = NIL;
|
||||
|
||||
RangeVar *vacuumRelation = NULL;
|
||||
foreach_declared_ptr(vacuumRelation, vacuumRelationList)
|
||||
VacuumRelation *vacuumRelation = NULL;
|
||||
foreach_declared_ptr(vacuumRelation, vacuumStmt->rels)
|
||||
{
|
||||
Oid relationId = InvalidOid;
|
||||
|
||||
/*
|
||||
* If skip_locked option is enabled, we are skipping that relation
|
||||
* if the lock for it is currently not available; else, we get the lock.
|
||||
* if the lock for it is currently not available; otherwise, we get the lock.
|
||||
*/
|
||||
Oid relationId = RangeVarGetRelidExtended(vacuumRelation,
|
||||
if (vacuumRelation->relation)
|
||||
{
|
||||
relationId = RangeVarGetRelidExtended(vacuumRelation->relation,
|
||||
lockMode,
|
||||
skipLocked ? RVR_SKIP_LOCKED : 0, NULL,
|
||||
NULL);
|
||||
}
|
||||
else if (OidIsValid(vacuumRelation->oid))
|
||||
{
|
||||
/* fall back to the Oid directly when provided */
|
||||
if (!skipLocked || ConditionalLockRelationOid(vacuumRelation->oid, lockMode))
|
||||
{
|
||||
if (!skipLocked)
|
||||
{
|
||||
LockRelationOid(vacuumRelation->oid, lockMode);
|
||||
}
|
||||
relationId = vacuumRelation->oid;
|
||||
}
|
||||
}
|
||||
|
||||
if (OidIsValid(relationId))
|
||||
{
|
||||
relationIdList = lappend_oid(relationIdList, relationId);
|
||||
CitusVacuumRelation *relation = palloc(sizeof(CitusVacuumRelation));
|
||||
relation->vacuumRelation = vacuumRelation;
|
||||
relation->relationId = relationId;
|
||||
relationList = lappend(relationList, relation);
|
||||
}
|
||||
}
|
||||
|
||||
return relationIdList;
|
||||
return relationList;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -161,12 +186,13 @@ VacuumRelationIdList(VacuumStmt *vacuumStmt, CitusVacuumParams vacuumParams)
|
|||
* otherwise, it returns false.
|
||||
*/
|
||||
static bool
|
||||
IsDistributedVacuumStmt(List *vacuumRelationIdList)
|
||||
IsDistributedVacuumStmt(List *vacuumRelationList)
|
||||
{
|
||||
Oid relationId = InvalidOid;
|
||||
foreach_declared_oid(relationId, vacuumRelationIdList)
|
||||
CitusVacuumRelation *vacuumRelation = NULL;
|
||||
foreach_declared_ptr(vacuumRelation, vacuumRelationList)
|
||||
{
|
||||
if (OidIsValid(relationId) && IsCitusTable(relationId))
|
||||
if (OidIsValid(vacuumRelation->relationId) &&
|
||||
IsCitusTable(vacuumRelation->relationId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -181,24 +207,31 @@ IsDistributedVacuumStmt(List *vacuumRelationIdList)
|
|||
* if they are citus tables.
|
||||
*/
|
||||
static void
|
||||
ExecuteVacuumOnDistributedTables(VacuumStmt *vacuumStmt, List *relationIdList,
|
||||
ExecuteVacuumOnDistributedTables(VacuumStmt *vacuumStmt, List *relationList,
|
||||
CitusVacuumParams vacuumParams)
|
||||
{
|
||||
int relationIndex = 0;
|
||||
|
||||
Oid relationId = InvalidOid;
|
||||
foreach_declared_oid(relationId, relationIdList)
|
||||
CitusVacuumRelation *vacuumRelationEntry = NULL;
|
||||
foreach_declared_ptr(vacuumRelationEntry, relationList)
|
||||
{
|
||||
Oid relationId = vacuumRelationEntry->relationId;
|
||||
VacuumRelation *vacuumRelation = vacuumRelationEntry->vacuumRelation;
|
||||
|
||||
RangeVar *relation = vacuumRelation->relation;
|
||||
if (relation != NULL && !relation->inh)
|
||||
{
|
||||
/* ONLY specified, so don't recurse to shard placements */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsCitusTable(relationId))
|
||||
{
|
||||
List *vacuumColumnList = VacuumColumnList(vacuumStmt, relationIndex);
|
||||
List *vacuumColumnList = vacuumRelation->va_cols;
|
||||
List *taskList = VacuumTaskList(relationId, vacuumParams, vacuumColumnList);
|
||||
|
||||
/* local execution is not implemented for VACUUM commands */
|
||||
bool localExecutionSupported = false;
|
||||
ExecuteUtilityTaskList(taskList, localExecutionSupported);
|
||||
}
|
||||
relationIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -484,39 +517,6 @@ DeparseVacuumColumnNames(List *columnNameList)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* VacuumColumnList returns list of columns from relation
|
||||
* in the vacuum statement at specified relationIndex.
|
||||
*/
|
||||
static List *
|
||||
VacuumColumnList(VacuumStmt *vacuumStmt, int relationIndex)
|
||||
{
|
||||
VacuumRelation *vacuumRelation = (VacuumRelation *) list_nth(vacuumStmt->rels,
|
||||
relationIndex);
|
||||
|
||||
return vacuumRelation->va_cols;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ExtractVacuumTargetRels returns list of target
|
||||
* relations from vacuum statement.
|
||||
*/
|
||||
static List *
|
||||
ExtractVacuumTargetRels(VacuumStmt *vacuumStmt)
|
||||
{
|
||||
List *vacuumList = NIL;
|
||||
|
||||
VacuumRelation *vacuumRelation = NULL;
|
||||
foreach_declared_ptr(vacuumRelation, vacuumStmt->rels)
|
||||
{
|
||||
vacuumList = lappend(vacuumList, vacuumRelation->relation);
|
||||
}
|
||||
|
||||
return vacuumList;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* VacuumStmtParams returns a CitusVacuumParams based on the supplied VacuumStmt.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1802,6 +1802,67 @@ NOTICE: renaming the new table to pg18_nn.generated_stored_ref
|
|||
(4 rows)
|
||||
|
||||
ROLLBACK;
|
||||
-- PG18 Feature: VACUUM/ANALYZE support ONLY to limit processing to the parent.
|
||||
-- For Citus, ensure ONLY does not trigger shard propagation.
|
||||
-- PG18 commit: https://github.com/postgres/postgres/commit/62ddf7ee9
|
||||
CREATE SCHEMA pg18_vacuum_part;
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
CREATE TABLE vac_analyze_only (a int);
|
||||
SELECT create_distributed_table('vac_analyze_only', 'a');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
INSERT INTO vac_analyze_only VALUES (1), (2), (3);
|
||||
ANALYZE vac_analyze_only;
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_analyze) AS analyze_before_only
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%'
|
||||
\gset
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
ANALYZE ONLY vac_analyze_only;
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_analyze) = :'analyze_before_only' AS analyze_only_skipped
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%';
|
||||
analyze_only_skipped
|
||||
---------------------------------------------------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
VACUUM vac_analyze_only;
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_vacuum) AS vacuum_before_only
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%'
|
||||
\gset
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
VACUUM ONLY vac_analyze_only;
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_vacuum) = :'vacuum_before_only' AS vacuum_only_skipped
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%';
|
||||
vacuum_only_skipped
|
||||
---------------------------------------------------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
DROP SCHEMA pg18_vacuum_part CASCADE;
|
||||
NOTICE: drop cascades to table vac_analyze_only
|
||||
SET search_path TO pg18_nn;
|
||||
-- END PG18 Feature: VACUUM/ANALYZE recurse into inheritance children by default
|
||||
-- cleanup with minimum verbosity
|
||||
SET client_min_messages TO ERROR;
|
||||
RESET search_path;
|
||||
|
|
|
|||
|
|
@ -1120,6 +1120,61 @@ BEGIN;
|
|||
SELECT * FROM generated_stored_ref;
|
||||
ROLLBACK;
|
||||
|
||||
-- PG18 Feature: VACUUM/ANALYZE support ONLY to limit processing to the parent.
|
||||
-- For Citus, ensure ONLY does not trigger shard propagation.
|
||||
-- PG18 commit: https://github.com/postgres/postgres/commit/62ddf7ee9
|
||||
CREATE SCHEMA pg18_vacuum_part;
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
CREATE TABLE vac_analyze_only (a int);
|
||||
SELECT create_distributed_table('vac_analyze_only', 'a');
|
||||
INSERT INTO vac_analyze_only VALUES (1), (2), (3);
|
||||
|
||||
ANALYZE vac_analyze_only;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_analyze) AS analyze_before_only
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%'
|
||||
\gset
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
ANALYZE ONLY vac_analyze_only;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_analyze) = :'analyze_before_only' AS analyze_only_skipped
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%';
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
VACUUM vac_analyze_only;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_vacuum) AS vacuum_before_only
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%'
|
||||
\gset
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
VACUUM ONLY vac_analyze_only;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
SELECT max(last_vacuum) = :'vacuum_before_only' AS vacuum_only_skipped
|
||||
FROM pg_stat_all_tables
|
||||
WHERE relname LIKE 'vac_analyze_only_%';
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path TO pg18_vacuum_part;
|
||||
DROP SCHEMA pg18_vacuum_part CASCADE;
|
||||
SET search_path TO pg18_nn;
|
||||
-- END PG18 Feature: VACUUM/ANALYZE recurse into inheritance children by default
|
||||
|
||||
-- cleanup with minimum verbosity
|
||||
SET client_min_messages TO ERROR;
|
||||
RESET search_path;
|
||||
|
|
|
|||
Loading…
Reference in New Issue