41
41
#include "distributed/metadata_utility.h"
42
42
#include "distributed/multi_executor.h"
43
43
#include "distributed/relation_access_tracking.h"
44
+ #include "distributed/serialize_distributed_ddls.h"
44
45
#include "distributed/worker_protocol.h"
45
46
#include "distributed/worker_transaction.h"
46
47
@@ -248,6 +249,9 @@ IsSetTablespaceStatement(AlterDatabaseStmt *stmt)
248
249
*
249
250
* In this stage we can prepare the commands that need to be run on all workers to grant
250
251
* on databases.
252
+ *
253
+ * We also serialize database commands globally by acquiring a Citus specific advisory
254
+ * lock based on OCLASS_DATABASE on the first primary worker node.
251
255
*/
252
256
List *
253
257
PreprocessAlterDatabaseStmt (Node * node , const char * queryString ,
@@ -264,6 +268,7 @@ PreprocessAlterDatabaseStmt(Node *node, const char *queryString,
264
268
}
265
269
266
270
EnsureCoordinator ();
271
+ SerializeDistributedDDLsOnObjectClassObject (OCLASS_DATABASE , stmt -> dbname );
267
272
268
273
char * sql = DeparseTreeNode ((Node * ) stmt );
269
274
@@ -291,11 +296,14 @@ PreprocessAlterDatabaseStmt(Node *node, const char *queryString,
291
296
#if PG_VERSION_NUM >= PG_VERSION_15
292
297
293
298
/*
294
- * PreprocessAlterDatabaseSetStmt is executed before the statement is applied to the local
295
- * postgres instance.
299
+ * PreprocessAlterDatabaseRefreshCollStmt is executed before the statement is applied to
300
+ * the local postgres instance.
296
301
*
297
302
* In this stage we can prepare the commands that need to be run on all workers to grant
298
303
* on databases.
304
+ *
305
+ * We also serialize database commands globally by acquiring a Citus specific advisory
306
+ * lock based on OCLASS_DATABASE on the first primary worker node.
299
307
*/
300
308
List *
301
309
PreprocessAlterDatabaseRefreshCollStmt (Node * node , const char * queryString ,
@@ -312,6 +320,7 @@ PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString,
312
320
}
313
321
314
322
EnsureCoordinator ();
323
+ SerializeDistributedDDLsOnObjectClassObject (OCLASS_DATABASE , stmt -> dbname );
315
324
316
325
char * sql = DeparseTreeNode ((Node * ) stmt );
317
326
@@ -325,8 +334,51 @@ PreprocessAlterDatabaseRefreshCollStmt(Node *node, const char *queryString,
325
334
326
335
#endif
327
336
337
+
328
338
/*
329
- * PreprocessAlterDatabaseRenameStmt is executed before the statement is applied to the local
339
+ * PreprocessAlterDatabaseRenameStmt is executed before the statement is applied to
340
+ * the local postgres instance.
341
+ *
342
+ * We also serialize database commands globally by acquiring a Citus specific advisory
343
+ * lock based on OCLASS_DATABASE on the first primary worker node.
344
+ *
345
+ * We acquire this lock here instead of PostprocessAlterDatabaseRenameStmt because the
346
+ * command renames the database and SerializeDistributedDDLsOnObjectClass resolves the
347
+ * object on workers based on database name. For this reason, we need to acquire the lock
348
+ * before the command is applied to the local postgres instance.
349
+ */
350
+ List *
351
+ PreprocessAlterDatabaseRenameStmt (Node * node , const char * queryString ,
352
+ ProcessUtilityContext processUtilityContext )
353
+ {
354
+ bool missingOk = true;
355
+ RenameStmt * stmt = castNode (RenameStmt , node );
356
+ ObjectAddress * dbAddress = GetDatabaseAddressFromDatabaseName (stmt -> subname ,
357
+ missingOk );
358
+
359
+ if (!ShouldPropagate () || !IsAnyObjectDistributed (list_make1 (dbAddress )))
360
+ {
361
+ return NIL ;
362
+ }
363
+
364
+ EnsureCoordinator ();
365
+
366
+ /*
367
+ * Different than other ALTER DATABASE commands, we first acquire a lock
368
+ * by providing InvalidOid because we want ALTER TABLE .. RENAME TO ..
369
+ * commands to block not only with ALTER DATABASE operations but also
370
+ * with CREATE DATABASE operations because they might cause name conflicts
371
+ * and that could also cause deadlocks too.
372
+ */
373
+ SerializeDistributedDDLsOnObjectClass (OCLASS_DATABASE );
374
+ SerializeDistributedDDLsOnObjectClassObject (OCLASS_DATABASE , stmt -> subname );
375
+
376
+ return NIL ;
377
+ }
378
+
379
+
380
+ /*
381
+ * PostprocessAlterDatabaseRenameStmt is executed after the statement is applied to the local
330
382
* postgres instance. In this stage we prepare ALTER DATABASE RENAME statement to be run on
331
383
* all workers.
332
384
*/
@@ -361,6 +413,9 @@ PostprocessAlterDatabaseRenameStmt(Node *node, const char *queryString)
361
413
*
362
414
* In this stage we can prepare the commands that need to be run on all workers to grant
363
415
* on databases.
416
+ *
417
+ * We also serialize database commands globally by acquiring a Citus specific advisory
418
+ * lock based on OCLASS_DATABASE on the first primary worker node.
364
419
*/
365
420
List *
366
421
PreprocessAlterDatabaseSetStmt (Node * node , const char * queryString ,
@@ -377,6 +432,7 @@ PreprocessAlterDatabaseSetStmt(Node *node, const char *queryString,
377
432
}
378
433
379
434
EnsureCoordinator ();
435
+ SerializeDistributedDDLsOnObjectClassObject (OCLASS_DATABASE , stmt -> dbname );
380
436
381
437
char * sql = DeparseTreeNode ((Node * ) stmt );
382
438
@@ -389,12 +445,15 @@ PreprocessAlterDatabaseSetStmt(Node *node, const char *queryString,
389
445
390
446
391
447
/*
392
- * PostprocessAlterDatabaseStmt is executed before the statement is applied to the local
448
+ * PreprocessCreateDatabaseStmt is executed before the statement is applied to the local
393
449
* Postgres instance.
394
450
*
395
451
* In this stage, we perform validations that we want to ensure before delegating to
396
452
* previous utility hooks because it might not be convenient to throw an error in an
397
453
* implicit transaction that creates a database.
454
+ *
455
+ * We also serialize database commands globally by acquiring a Citus specific advisory
456
+ * lock based on OCLASS_DATABASE on the first primary worker node.
398
457
*/
399
458
List *
400
459
PreprocessCreateDatabaseStmt (Node * node , const char * queryString ,
@@ -405,11 +464,13 @@ PreprocessCreateDatabaseStmt(Node *node, const char *queryString,
405
464
return NIL ;
406
465
}
407
466
408
- EnsureCoordinator ();
467
+ EnsurePropagationToCoordinator ();
409
468
410
469
CreatedbStmt * stmt = castNode (CreatedbStmt , node );
411
470
EnsureSupportedCreateDatabaseCommand (stmt );
412
471
472
+ SerializeDistributedDDLsOnObjectClass (OCLASS_DATABASE );
473
+
413
474
return NIL ;
414
475
}
415
476
@@ -430,7 +491,7 @@ PostprocessCreateDatabaseStmt(Node *node, const char *queryString)
430
491
return NIL ;
431
492
}
432
493
433
- EnsureCoordinator ();
494
+ EnsurePropagationToCoordinator ();
434
495
435
496
/*
436
497
* Given that CREATE DATABASE doesn't support "IF NOT EXISTS" and we're
@@ -448,16 +509,19 @@ PostprocessCreateDatabaseStmt(Node *node, const char *queryString)
448
509
(void * ) createDatabaseCommand ,
449
510
ENABLE_DDL_PROPAGATION );
450
511
451
- return NontransactionalNodeDDLTaskList (NON_COORDINATOR_NODES , commands );
512
+ return NontransactionalNodeDDLTaskList (REMOTE_NODES , commands );
452
513
}
453
514
454
515
455
516
/*
456
- * PreprocessDropDatabaseStmt is executed after the statement is applied to the local
517
+ * PreprocessDropDatabaseStmt is executed before the statement is applied to the local
457
518
* postgres instance. In this stage we can prepare the commands that need to be run on
458
519
* all workers to drop the database. Since the DROP DATABASE statement gives error in
459
520
* transaction context, we need to use NontransactionalNodeDDLTaskList to send the
460
521
* DROP DATABASE statement to the workers.
522
+ *
523
+ * We also serialize database commands globally by acquiring a Citus specific advisory
524
+ * lock based on OCLASS_DATABASE on the first primary worker node.
461
525
*/
462
526
List *
463
527
PreprocessDropDatabaseStmt (Node * node , const char * queryString ,
@@ -468,7 +532,7 @@ PreprocessDropDatabaseStmt(Node *node, const char *queryString,
468
532
return NIL ;
469
533
}
470
534
471
- EnsureCoordinator ();
535
+ EnsurePropagationToCoordinator ();
472
536
473
537
DropdbStmt * stmt = (DropdbStmt * ) node ;
474
538
@@ -488,13 +552,15 @@ PreprocessDropDatabaseStmt(Node *node, const char *queryString,
488
552
return NIL ;
489
553
}
490
554
555
+ SerializeDistributedDDLsOnObjectClassObject (OCLASS_DATABASE , stmt -> dbname );
556
+
491
557
char * dropDatabaseCommand = DeparseTreeNode (node );
492
558
493
559
List * commands = list_make3 (DISABLE_DDL_PROPAGATION ,
494
560
(void * ) dropDatabaseCommand ,
495
561
ENABLE_DDL_PROPAGATION );
496
562
497
- return NontransactionalNodeDDLTaskList (NON_COORDINATOR_NODES , commands );
563
+ return NontransactionalNodeDDLTaskList (REMOTE_NODES , commands );
498
564
}
499
565
500
566
0 commit comments