|
10 | 10 | */ |
11 | 11 |
|
12 | 12 | #include <postgres.h> |
| 13 | + |
13 | 14 | #include <access/htup_details.h> |
14 | 15 | #include <catalog/dependency.h> |
15 | 16 | #include <catalog/namespace.h> |
16 | 17 | #include <catalog/pg_trigger.h> |
17 | 18 | #include <commands/trigger.h> |
| 19 | +#include <executor/spi.h> |
18 | 20 | #include <fmgr.h> |
| 21 | +#include <lib/stringinfo.h> |
19 | 22 | #include <nodes/makefuncs.h> |
| 23 | +#include <replication/slot.h> |
20 | 24 | #include <storage/lmgr.h> |
21 | 25 | #include <utils/acl.h> |
22 | 26 | #include <utils/builtins.h> |
|
46 | 50 | #define BUCKET_FUNCTION_SERIALIZE_VERSION 1 |
47 | 51 | #define CHECK_NAME_MATCH(name1, name2) (namestrcmp(name1, name2) == 0) |
48 | 52 |
|
| 53 | +TS_FUNCTION_INFO_V1(ts_has_invalidation_trigger); |
| 54 | + |
| 55 | +Datum |
| 56 | +ts_has_invalidation_trigger(PG_FUNCTION_ARGS) |
| 57 | +{ |
| 58 | + PG_RETURN_BOOL(has_invalidation_trigger(PG_GETARG_OID(0))); |
| 59 | +} |
| 60 | + |
49 | 61 | static void |
50 | 62 | init_scan_by_mat_hypertable_id(ScanIterator *iterator, const int32 mat_hypertable_id) |
51 | 63 | { |
@@ -193,6 +205,12 @@ hypertable_invalidation_log_delete(int32 raw_hypertable_id) |
193 | 205 | } |
194 | 206 | } |
195 | 207 |
|
| 208 | +void |
| 209 | +ts_get_invalidation_replication_slot_name(char *slotname, Size szslot) |
| 210 | +{ |
| 211 | + snprintf(slotname, szslot, "ts_%u_cagg", MyDatabaseId); |
| 212 | +} |
| 213 | + |
196 | 214 | void |
197 | 215 | ts_materialization_invalidation_log_delete_inner(int32 mat_hypertable_id) |
198 | 216 | { |
@@ -502,6 +520,37 @@ ts_continuous_agg_get_all_caggs_info(int32 raw_hypertable_id) |
502 | 520 | return all_caggs_info; |
503 | 521 | } |
504 | 522 |
|
| 523 | +/* |
| 524 | + * Return true if there is any continuous aggregate that is using WAL-based |
| 525 | + * invalidation collection. |
| 526 | + * |
| 527 | + * A hypertable is using the WAL-based invalidation collection if it has a |
| 528 | + * attached continuous aggregate but does not have an invalidation trigger. |
| 529 | + */ |
| 530 | +static bool |
| 531 | +hypertable_invalidation_slot_used(void) |
| 532 | +{ |
| 533 | + ScanIterator iterator = |
| 534 | + ts_scan_iterator_create(CONTINUOUS_AGG, AccessShareLock, CurrentMemoryContext); |
| 535 | + ts_scanner_foreach(&iterator) |
| 536 | + { |
| 537 | + bool isnull; |
| 538 | + Datum datum = slot_getattr(ts_scan_iterator_slot(&iterator), |
| 539 | + Anum_continuous_agg_raw_hypertable_id, |
| 540 | + &isnull); |
| 541 | + |
| 542 | + Assert(!isnull); |
| 543 | + Oid relid = ts_hypertable_id_to_relid(DatumGetInt32(datum), true); |
| 544 | + if (!has_invalidation_trigger(relid)) |
| 545 | + { |
| 546 | + ts_scan_iterator_close(&iterator); |
| 547 | + return true; |
| 548 | + } |
| 549 | + } |
| 550 | + ts_scan_iterator_close(&iterator); |
| 551 | + return false; |
| 552 | +} |
| 553 | + |
505 | 554 | TSDLLEXPORT ContinuousAggHypertableStatus |
506 | 555 | ts_continuous_agg_hypertable_status(int32 hypertable_id) |
507 | 556 | { |
@@ -829,6 +878,10 @@ drop_continuous_agg(FormData_continuous_agg *cadata, bool drop_user_view) |
829 | 878 | * |
830 | 879 | * AccessExclusiveLock is needed to drop triggers and also prevent |
831 | 880 | * concurrent DML commands. |
| 881 | + * |
| 882 | + * It is needed also in the case that we are using WAL-based invalidation |
| 883 | + * collection since we want to serialize create and drop of continuous |
| 884 | + * aggregates. |
832 | 885 | */ |
833 | 886 | if (drop_user_view) |
834 | 887 | user_view = get_and_lock_rel_by_name(&cadata->user_view_schema, |
@@ -856,17 +909,13 @@ drop_continuous_agg(FormData_continuous_agg *cadata, bool drop_user_view) |
856 | 909 | LockRelationOid(catalog_get_table_id(catalog, CONTINUOUS_AGGS_INVALIDATION_THRESHOLD), |
857 | 910 | RowExclusiveLock); |
858 | 911 |
|
859 | | - /* The trigger will be dropped if the hypertable still exists and no other |
| 912 | + /* The trigger will be dropped if it exists (it does not for WAL-based |
| 913 | + * invalidation collection), the hypertable still exists and no other |
860 | 914 | * caggs attached. */ |
861 | | - if (OidIsValid(raw_hypertable.objectId)) |
| 915 | + Oid tgoid = get_trigger_oid(raw_hypertable.objectId, CAGGINVAL_TRIGGER_NAME, true); |
| 916 | + if (OidIsValid(raw_hypertable.objectId) && OidIsValid(tgoid)) |
862 | 917 | { |
863 | | - ObjectAddressSet(raw_hypertable_trig, |
864 | | - TriggerRelationId, |
865 | | - get_trigger_oid(raw_hypertable.objectId, |
866 | | - CAGGINVAL_TRIGGER_NAME, |
867 | | - false)); |
868 | | - |
869 | | - /* Raw hypertable is locked above */ |
| 918 | + ObjectAddressSet(raw_hypertable_trig, TriggerRelationId, tgoid); |
870 | 919 | LockRelationOid(raw_hypertable_trig.objectId, AccessExclusiveLock); |
871 | 920 | } |
872 | 921 | } |
@@ -924,6 +973,18 @@ drop_continuous_agg(FormData_continuous_agg *cadata, bool drop_user_view) |
924 | 973 | ts_hypertable_drop_trigger(raw_hypertable.objectId, CAGGINVAL_TRIGGER_NAME); |
925 | 974 | } |
926 | 975 |
|
| 976 | + /* |
| 977 | + * Drop invalidation slot if there are no hypertables using WAL-based |
| 978 | + * invalidation collection. |
| 979 | + * |
| 980 | + * This is important since there is no actor that reads the slot, which |
| 981 | + * means that the WAL cannot be pruned. |
| 982 | + */ |
| 983 | + char slot_name[TS_INVALIDATION_SLOT_NAME_MAX]; |
| 984 | + ts_get_invalidation_replication_slot_name(slot_name, sizeof(slot_name)); |
| 985 | + if (!hypertable_invalidation_slot_used() && SearchNamedReplicationSlot(slot_name, true) != NULL) |
| 986 | + ts_hypertable_drop_invalidation_replication_slot(slot_name); |
| 987 | + |
927 | 988 | if (OidIsValid(mat_hypertable.objectId)) |
928 | 989 | { |
929 | 990 | performDeletion(&mat_hypertable, DROP_CASCADE, 0); |
|
0 commit comments