Skip to content

Commit aed824d

Browse files
committed
Changes after the C-rabbit review.
Guard spock_conflict_stat.h include and improve conflict type validation
1 parent 0105fe2 commit aed824d

3 files changed

Lines changed: 88 additions & 16 deletions

File tree

.github/workflows/installcheck.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
version: latest
5454

5555
- name: Start docker cluster
56+
id: start_cluster
5657
run: |
5758
cd ${GITHUB_WORKSPACE}/tests/docker/
5859
# To minimize regression tests difference, override pgedge.env with
@@ -63,6 +64,22 @@ jobs:
6364
PGVER=${{ matrix.pgver }} DBUSER=regression DBNAME=regression \
6465
docker compose up --build --wait -d
6566
timeout-minutes: 20
67+
continue-on-error: true
68+
69+
- name: Diagnose cluster startup failure
70+
if: steps.start_cluster.outcome == 'failure'
71+
run: |
72+
cd ${GITHUB_WORKSPACE}/tests/docker/
73+
echo "=== Docker container status ==="
74+
docker compose ps -a
75+
for node in n1 n2 n3; do
76+
echo ""
77+
echo "=== Container logs: $node ==="
78+
docker compose logs pgedge-$node 2>&1 | tail -80 || true
79+
echo ""
80+
echo "=== PostgreSQL logfile: $node ==="
81+
docker compose cp pgedge-$node:/home/pgedge/logfile.log /dev/stdout 2>/dev/null | tail -80 || echo "(not available)"
82+
done
6683
6784
- name: Run installcheck on node n1
6885
id: installcheck

src/spock_apply_heap.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@
6464

6565
#include "spock_common.h"
6666
#include "spock_conflict.h"
67+
#if PG_VERSION_NUM >= 180000
6768
#include "spock_conflict_stat.h"
69+
#endif
6870
#include "spock_executor.h"
6971
#include "spock_node.h"
7072
#include "spock_proto_native.h"
@@ -1071,10 +1073,9 @@ spock_apply_heap_update(SpockRelation *rel, SpockTupleData *oldtup,
10711073
#if PG_VERSION_NUM >= 180000
10721074
if (!MyApplyWorker->use_try_block)
10731075
/*
1074-
* To avoid duplicated messages complain only in case we are on the
1075-
* successful path way. We don't count the conflict if something
1076-
* goes wrong already because the update logic is broken yet and
1077-
* this conflict may be misleading.
1076+
* To avoid duplicate messages, only report the conflict on the
1077+
* successful pathway. We skip counting when the update logic has
1078+
* already failed because the conflict would be misleading.
10781079
*/
10791080
spock_stat_report_subscription_conflict(MyApplyWorker->subid,
10801081
SPOCK_CT_UPDATE_MISSING);

src/spock_conflict_stat.c

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,29 @@
1616
*/
1717
#include "postgres.h"
1818

19-
#if PG_VERSION_NUM >= 180000
20-
2119
#include "funcapi.h"
2220
#include "utils/pgstat_internal.h"
2321

2422
#include "spock.h"
23+
24+
PG_FUNCTION_INFO_V1(spock_get_subscription_stats);
25+
PG_FUNCTION_INFO_V1(spock_reset_subscription_stats);
26+
27+
#if PG_VERSION_NUM >= 180000
2528
#include "spock_conflict_stat.h"
2629

2730
/*
2831
* Kind ID reserved for statistics of spock replication conflicts.
29-
* TODO: ask Michael Paquier about exact numbers and conflict detection
32+
* TODO: see https://wiki.postgresql.org/wiki/CustomCumulativeStats to choose
33+
* specific value in production
3034
*/
31-
#define SPOCK_PGSTAT_KIND_LRCONFLICTS 27
35+
#define SPOCK_PGSTAT_KIND_LRCONFLICTS 28
3236

3337
/* Shared memory wrapper for spock subscription conflict stats */
3438
typedef struct Spock_Stat_Subscription
3539
{
3640
PgStatShared_Common header;
37-
Spock_Stat_StatSubEntry stats;
41+
Spock_Stat_StatSubEntry stats;
3842
} Spock_Stat_Subscription;
3943

4044
/*
@@ -52,9 +56,6 @@ static const char *const SpockConflictStatColNames[SPOCK_CONFLICT_NUM_TYPES] = {
5256
[SPOCK_CT_DELETE_MISSING] = "confl_delete_missing",
5357
};
5458

55-
PG_FUNCTION_INFO_V1(spock_get_subscription_stats);
56-
PG_FUNCTION_INFO_V1(spock_reset_subscription_stats);
57-
5859
static bool spock_stat_subscription_flush_cb(PgStat_EntryRef *entry_ref,
5960
bool nowait);
6061
static void spock_stat_subscription_reset_timestamp_cb(
@@ -95,7 +96,15 @@ spock_stat_report_subscription_conflict(Oid subid, SpockConflictType type)
9596
PgStat_EntryRef *entry_ref;
9697
Spock_Stat_PendingSubEntry *pending;
9798

98-
Assert(type >= 0 && type < SPOCK_CONFLICT_NUM_TYPES);
99+
if (type != SPOCK_CT_UPDATE_MISSING)
100+
/*
101+
* Should happen only in development. Detect it as fast as possible
102+
* with the highest error level that does not crash the instance.
103+
*/
104+
ereport(ERROR,
105+
(errcode(ERRCODE_INTERNAL_ERROR),
106+
errmsg("unexpected conflict type %d reported for subscription %u",
107+
type, subid)));
99108

100109
entry_ref = pgstat_prep_pending_entry(SPOCK_PGSTAT_KIND_LRCONFLICTS,
101110
MyDatabaseId, subid, NULL);
@@ -109,13 +118,31 @@ spock_stat_report_subscription_conflict(Oid subid, SpockConflictType type)
109118
void
110119
spock_stat_create_subscription(Oid subid)
111120
{
121+
PgStat_EntryRef *ref;
122+
112123
/* Ensures that stats are dropped if transaction rolls back */
113124
pgstat_create_transactional(SPOCK_PGSTAT_KIND_LRCONFLICTS,
114125
MyDatabaseId, subid);
115126

116127
/* Create and initialize the subscription stats entry */
117-
pgstat_get_entry_ref(SPOCK_PGSTAT_KIND_LRCONFLICTS, MyDatabaseId, subid,
118-
true, NULL);
128+
ref = pgstat_get_entry_ref(SPOCK_PGSTAT_KIND_LRCONFLICTS, MyDatabaseId, subid,
129+
true, NULL);
130+
131+
if (pg_atomic_read_u32(&ref->shared_entry->refcount) != 2)
132+
/*
133+
* Should never happen: a new subscription stats entry should have
134+
* exactly two references (the hashtable entry and our own). A higher
135+
* count means a stale entry from a previous subscription with the same
136+
* OID was not properly cleaned up.
137+
*/
138+
ereport(WARNING,
139+
(errmsg("conflict statistics entry for subscription %u "
140+
"already has %u references",
141+
subid,
142+
pg_atomic_read_u32(&ref->shared_entry->refcount)),
143+
errhint("This may indicate that a previous subscription with "
144+
"the same OID was not fully dropped.")));
145+
119146
pgstat_reset_entry(SPOCK_PGSTAT_KIND_LRCONFLICTS, MyDatabaseId, subid, 0);
120147
}
121148

@@ -247,9 +274,36 @@ spock_stat_subscription_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
247274
}
248275

249276
static void
250-
spock_stat_subscription_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
277+
spock_stat_subscription_reset_timestamp_cb(PgStatShared_Common *header,
278+
TimestampTz ts)
251279
{
252280
((Spock_Stat_Subscription *) header)->stats.stat_reset_timestamp = ts;
253281
}
254282

255283
#endif /* PG_VERSION_NUM >= 180000 */
284+
285+
#if PG_VERSION_NUM < 180000
286+
287+
/*
288+
* XXX: implement conflict statistics gathering, if needed
289+
*/
290+
291+
Datum
292+
spock_get_subscription_stats(PG_FUNCTION_ARGS)
293+
{
294+
ereport(ERROR,
295+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
296+
errmsg("spock conflict statistics require PostgreSQL 18 or later")));
297+
PG_RETURN_NULL(); /* unreachable; suppress compiler warning */
298+
}
299+
300+
Datum
301+
spock_reset_subscription_stats(PG_FUNCTION_ARGS)
302+
{
303+
ereport(ERROR,
304+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
305+
errmsg("spock conflict statistics require PostgreSQL 18 or later")));
306+
PG_RETURN_NULL(); /* unreachable; suppress compiler warning */
307+
}
308+
309+
#endif /* PG_VERSION_NUM < 180000 */

0 commit comments

Comments
 (0)