diff --git a/src/backend/distributed/commands/vacuum.c b/src/backend/distributed/commands/vacuum.c
index 706fea00c..55b30ebfb 100644
--- a/src/backend/distributed/commands/vacuum.c
+++ b/src/backend/distributed/commands/vacuum.c
@@ -30,6 +30,7 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "postmaster/bgworker_internals.h"
+#include "access/xact.h"
#define VACUUM_PARALLEL_NOTSET -2
@@ -51,14 +52,18 @@ typedef struct CitusVacuumParams
} CitusVacuumParams;
/* Local functions forward declarations for processing distributed table commands */
-static bool IsDistributedVacuumStmt(int vacuumOptions, List *vacuumRelationIdList);
+static bool IsDistributedVacuumStmt(int vacuumOptions, List *VacuumCitusRelationIdList);
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,
+ CitusVacuumParams vacuumParams);
static CitusVacuumParams VacuumStmtParams(VacuumStmt *vacstmt);
+static List * VacuumCitusRelationIdList(VacuumStmt *vacuumStmt, CitusVacuumParams
+ vacuumParams);
/*
* PostprocessVacuumStmt processes vacuum statements that may need propagation to
@@ -73,29 +78,97 @@ static CitusVacuumParams VacuumStmtParams(VacuumStmt *vacstmt);
void
PostprocessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand)
{
- int relationIndex = 0;
- List *vacuumRelationList = ExtractVacuumTargetRels(vacuumStmt);
- List *relationIdList = NIL;
CitusVacuumParams vacuumParams = VacuumStmtParams(vacuumStmt);
- LOCKMODE lockMode = (vacuumParams.options & VACOPT_FULL) ? AccessExclusiveLock :
- ShareUpdateExclusiveLock;
- int executedVacuumCount = 0;
+ const char *stmtName = (vacuumParams.options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
- RangeVar *vacuumRelation = NULL;
- foreach_ptr(vacuumRelation, vacuumRelationList)
+ /*
+ * No table in the vacuum statement means vacuuming all relations
+ * which is not supported by citus.
+ */
+ if (list_length(vacuumStmt->rels) == 0)
{
- Oid relationId = RangeVarGetRelid(vacuumRelation, lockMode, false);
- relationIdList = lappend_oid(relationIdList, relationId);
+ /* WARN for unqualified VACUUM commands */
+ ereport(WARNING, (errmsg("not propagating %s command to worker nodes", stmtName),
+ errhint("Provide a specific table in order to %s "
+ "distributed tables.", stmtName)));
}
+
+ List *citusRelationIdList = VacuumCitusRelationIdList(vacuumStmt, vacuumParams);
+ if (list_length(citusRelationIdList) == 0)
+ {
+ return;
+ }
+
+ if (vacuumParams.options & VACOPT_VACUUM)
+ {
+ /*
+ * We commit the current transaction here so that the global lock
+ * taken from the shell table for VACUUM is released, which would block execution
+ * of shard placements. We don't do this in case of "ANALYZE
" command because
+ * its semantics are different than VACUUM and it doesn't acquire the global lock.
+ */
+ CommitTransactionCommand();
+ StartTransactionCommand();
+ }
+
+ /*
+ * Here we get the relation list again because we might have
+ * closed the current transaction and the memory context got reset.
+ * Vacuum's context is PortalContext, which lasts for the whole session
+ * so committing/starting a new transaction doesn't affect it.
+ */
+ citusRelationIdList = VacuumCitusRelationIdList(vacuumStmt, vacuumParams);
bool distributedVacuumStmt = IsDistributedVacuumStmt(vacuumParams.options,
- relationIdList);
+ citusRelationIdList);
if (!distributedVacuumStmt)
{
return;
}
- /* execute vacuum on distributed tables */
+ ExecuteVacuumOnDistributedTables(vacuumStmt, citusRelationIdList, vacuumParams);
+}
+
+
+/*
+ * VacuumCitusRelationIdList returns the oid of the relations in the given vacuum statement.
+ */
+static List *
+VacuumCitusRelationIdList(VacuumStmt *vacuumStmt, CitusVacuumParams vacuumParams)
+{
+ LOCKMODE lockMode = (vacuumParams.options & VACOPT_FULL) ? AccessExclusiveLock :
+ ShareUpdateExclusiveLock;
+
+ List *vacuumRelationList = ExtractVacuumTargetRels(vacuumStmt);
+
+ List *relationIdList = NIL;
+
+ RangeVar *vacuumRelation = NULL;
+ foreach_ptr(vacuumRelation, vacuumRelationList)
+ {
+ Oid relationId = RangeVarGetRelid(vacuumRelation, lockMode, false);
+ if (!IsCitusTable(relationId))
+ {
+ continue;
+ }
+ relationIdList = lappend_oid(relationIdList, relationId);
+ }
+
+ return relationIdList;
+}
+
+
+/*
+ * ExecuteVacuumOnDistributedTables executes the vacuum for the shard placements of given tables
+ * if they are citus tables.
+ */
+static void
+ExecuteVacuumOnDistributedTables(VacuumStmt *vacuumStmt, List *relationIdList,
+ CitusVacuumParams vacuumParams)
+{
+ int relationIndex = 0;
+ int executedVacuumCount = 0;
+
Oid relationId = InvalidOid;
foreach_oid(relationId, relationIdList)
{
@@ -137,27 +210,16 @@ PostprocessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand)
* false otherwise.
*/
static bool
-IsDistributedVacuumStmt(int vacuumOptions, List *vacuumRelationIdList)
+IsDistributedVacuumStmt(int vacuumOptions, List *VacuumCitusRelationIdList)
{
- const char *stmtName = (vacuumOptions & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
bool distributeStmt = false;
int distributedRelationCount = 0;
- /*
- * No table in the vacuum statement means vacuuming all relations
- * which is not supported by citus.
- */
- int vacuumedRelationCount = list_length(vacuumRelationIdList);
- if (vacuumedRelationCount == 0)
- {
- /* WARN for unqualified VACUUM commands */
- ereport(WARNING, (errmsg("not propagating %s command to worker nodes", stmtName),
- errhint("Provide a specific table in order to %s "
- "distributed tables.", stmtName)));
- }
+ const char *stmtName = (vacuumOptions & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
+
Oid relationId = InvalidOid;
- foreach_oid(relationId, vacuumRelationIdList)
+ foreach_oid(relationId, VacuumCitusRelationIdList)
{
if (OidIsValid(relationId) && IsCitusTable(relationId))
{
diff --git a/src/test/regress/expected/single_node.out b/src/test/regress/expected/single_node.out
index d0610d6cf..75b7eec03 100644
--- a/src/test/regress/expected/single_node.out
+++ b/src/test/regress/expected/single_node.out
@@ -112,6 +112,14 @@ BEGIN;
ROLLBACK;
VACUUM test;
+VACUUM test, test_2;
+VACUUM ref, test;
+VACUUM ANALYZE test(x);
+ANALYZE ref;
+ANALYZE test_2;
+VACUUM local;
+VACUUM local, ref, test, test_2;
+VACUUM FULL test, ref;
BEGIN;
ALTER TABLE test ADD COLUMN z INT DEFAULT 66;
SELECT count(*) FROM test WHERE z = 66;
diff --git a/src/test/regress/sql/single_node.sql b/src/test/regress/sql/single_node.sql
index 59463bcce..c6a734e8a 100644
--- a/src/test/regress/sql/single_node.sql
+++ b/src/test/regress/sql/single_node.sql
@@ -58,6 +58,14 @@ BEGIN;
ROLLBACK;
VACUUM test;
+VACUUM test, test_2;
+VACUUM ref, test;
+VACUUM ANALYZE test(x);
+ANALYZE ref;
+ANALYZE test_2;
+VACUUM local;
+VACUUM local, ref, test, test_2;
+VACUUM FULL test, ref;
BEGIN;
ALTER TABLE test ADD COLUMN z INT DEFAULT 66;