0001-REALLOCATE_BITMAPSETS-manual-compile-time-option-v1.patch
application/octet-stream
Filename: 0001-REALLOCATE_BITMAPSETS-manual-compile-time-option-v1.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: REALLOCATE_BITMAPSETS manual compile-time option
| File | + | − |
|---|---|---|
| src/backend/nodes/bitmapset.c | 132 | 14 |
| src/include/pg_config_manual.h | 6 | 0 |
From 5a18e880fb53ee5b5a0be092b1cb796636dbb60c Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Sun, 19 Nov 2023 01:03:12 +0200
Subject: [PATCH 1/2] REALLOCATE_BITMAPSETS manual compile-time option
This option forces each bitmapset modification to reallocate bitmapset. This
is useful for debugging hangling pointers to bitmapset's.
Discussion: https://postgr.es/m/CAMbWs4_wJthNtYBL+SsebpgF-5L2r5zFFk6xYbS0A78GKOTFHw@mail.gmail.com
---
src/backend/nodes/bitmapset.c | 146 +++++++++++++++++++++++++++++----
src/include/pg_config_manual.h | 6 ++
2 files changed, 138 insertions(+), 14 deletions(-)
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index 704879f5660..8be3e3e2c5e 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -84,6 +84,7 @@ bms_copy(const Bitmapset *a)
if (a == NULL)
return NULL;
+ Assert(IsA(a, Bitmapset));
size = BITMAPSET_SIZE(a->nwords);
result = (Bitmapset *) palloc(size);
memcpy(result, a, size);
@@ -98,8 +99,8 @@ bms_equal(const Bitmapset *a, const Bitmapset *b)
{
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -139,8 +140,8 @@ bms_compare(const Bitmapset *a, const Bitmapset *b)
{
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -215,6 +216,9 @@ bms_union(const Bitmapset *a, const Bitmapset *b)
int otherlen;
int i;
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
+
/* Handle cases where either input is NULL */
if (a == NULL)
return bms_copy(b);
@@ -253,9 +257,13 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b)
int resultlen;
int i;
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
+
/* Handle cases where either input is NULL */
if (a == NULL || b == NULL)
return NULL;
+
/* Identify shorter and longer input; copy the shorter one */
if (a->nwords <= b->nwords)
{
@@ -299,8 +307,8 @@ bms_difference(const Bitmapset *a, const Bitmapset *b)
Bitmapset *result;
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -308,6 +316,8 @@ bms_difference(const Bitmapset *a, const Bitmapset *b)
if (b == NULL)
return bms_copy(a);
+ Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
/*
* In Postgres' usage, an empty result is a very common case, so it's
* worth optimizing for that by testing bms_nonempty_difference(). This
@@ -364,8 +374,8 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
{
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -373,6 +383,8 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
if (b == NULL)
return false;
+ Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
/* 'a' can't be a subset of 'b' if it contains more words */
if (a->nwords > b->nwords)
return false;
@@ -399,8 +411,8 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
int shortlen;
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -411,6 +423,9 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
}
if (b == NULL)
return BMS_SUBSET2;
+
+ Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
/* Check common words */
result = BMS_EQUAL; /* status so far */
shortlen = Min(a->nwords, b->nwords);
@@ -467,6 +482,9 @@ bms_is_member(int x, const Bitmapset *a)
elog(ERROR, "negative bitmapset member not allowed");
if (a == NULL)
return false;
+
+ Assert(IsA(a, Bitmapset));
+
wordnum = WORDNUM(x);
bitnum = BITNUM(x);
if (wordnum >= a->nwords)
@@ -495,6 +513,8 @@ bms_member_index(Bitmapset *a, int x)
if (!bms_is_member(x, a))
return -1;
+ Assert(IsA(a, Bitmapset));
+
wordnum = WORDNUM(x);
bitnum = BITNUM(x);
@@ -529,6 +549,9 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
int shortlen;
int i;
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
+
/* Handle cases where either input is NULL */
if (a == NULL || b == NULL)
return false;
@@ -553,6 +576,8 @@ bms_overlap_list(const Bitmapset *a, const List *b)
int wordnum,
bitnum;
+ Assert(a == NULL || IsA(a, Bitmapset));
+
if (a == NULL || b == NIL)
return false;
@@ -582,8 +607,8 @@ bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
{
int i;
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -617,6 +642,9 @@ bms_singleton_member(const Bitmapset *a)
if (a == NULL)
elog(ERROR, "bitmapset is empty");
+
+ Assert(IsA(a, Bitmapset));
+
nwords = a->nwords;
wordnum = 0;
do
@@ -657,6 +685,7 @@ bms_get_singleton_member(const Bitmapset *a, int *member)
if (a == NULL)
return false;
+ Assert(IsA(a, Bitmapset));
nwords = a->nwords;
wordnum = 0;
do
@@ -690,6 +719,7 @@ bms_num_members(const Bitmapset *a)
if (a == NULL)
return 0;
+ Assert(IsA(a, Bitmapset));
nwords = a->nwords;
wordnum = 0;
do
@@ -717,6 +747,7 @@ bms_membership(const Bitmapset *a)
if (a == NULL)
return BMS_EMPTY_SET;
+ Assert(IsA(a, Bitmapset));
nwords = a->nwords;
wordnum = 0;
do
@@ -759,6 +790,7 @@ bms_add_member(Bitmapset *a, int x)
elog(ERROR, "negative bitmapset member not allowed");
if (a == NULL)
return bms_make_singleton(x);
+ Assert(IsA(a, Bitmapset));
wordnum = WORDNUM(x);
bitnum = BITNUM(x);
@@ -767,8 +799,15 @@ bms_add_member(Bitmapset *a, int x)
{
int oldnwords = a->nwords;
int i;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(wordnum + 1));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#else
a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1));
+#endif
a->nwords = wordnum + 1;
/* zero out the enlarged portion */
i = oldnwords;
@@ -777,6 +816,16 @@ bms_add_member(Bitmapset *a, int x)
a->words[i] = 0;
} while (++i < a->nwords);
}
+#ifdef REALLOCATE_BITMAPSETS
+ else
+ {
+ Bitmapset *tmp = a;
+
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+ }
+#endif
a->words[wordnum] |= ((bitmapword) 1 << bitnum);
return a;
@@ -794,14 +843,24 @@ bms_del_member(Bitmapset *a, int x)
{
int wordnum,
bitnum;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+#endif
if (x < 0)
elog(ERROR, "negative bitmapset member not allowed");
if (a == NULL)
return NULL;
+ Assert(IsA(a, Bitmapset));
wordnum = WORDNUM(x);
bitnum = BITNUM(x);
+#ifdef REALLOCATE_BITMAPSETS
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#endif
+
/* member can't exist. Return 'a' unmodified */
if (unlikely(wordnum >= a->nwords))
return a;
@@ -839,6 +898,9 @@ bms_add_members(Bitmapset *a, const Bitmapset *b)
int otherlen;
int i;
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
+
/* Handle cases where either input is NULL */
if (a == NULL)
return bms_copy(b);
@@ -852,6 +914,13 @@ bms_add_members(Bitmapset *a, const Bitmapset *b)
}
else
{
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#endif
result = a;
other = b;
}
@@ -884,6 +953,8 @@ bms_add_range(Bitmapset *a, int lower, int upper)
ushiftbits,
wordnum;
+ Assert(a == NULL || IsA(a, Bitmapset));
+
/* do nothing if nothing is called for, without further checking */
if (upper < lower)
return a;
@@ -902,9 +973,16 @@ bms_add_range(Bitmapset *a, int lower, int upper)
{
int oldnwords = a->nwords;
int i;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(uwordnum + 1));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#else
/* ensure we have enough words to store the upper bit */
a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1));
+#endif
a->nwords = uwordnum + 1;
/* zero out the enlarged portion */
i = oldnwords;
@@ -953,6 +1031,12 @@ bms_int_members(Bitmapset *a, const Bitmapset *b)
int lastnonzero;
int shortlen;
int i;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+#endif
+
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
/* Handle cases where either input is NULL */
if (a == NULL)
@@ -962,6 +1046,13 @@ bms_int_members(Bitmapset *a, const Bitmapset *b)
pfree(a);
return NULL;
}
+
+#ifdef REALLOCATE_BITMAPSETS
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#endif
+
/* Intersect b into a; we need never copy */
shortlen = Min(a->nwords, b->nwords);
lastnonzero = -1;
@@ -993,15 +1084,25 @@ Bitmapset *
bms_del_members(Bitmapset *a, const Bitmapset *b)
{
int i;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+#endif
- Assert(a == NULL || a->words[a->nwords - 1] != 0);
- Assert(b == NULL || b->words[b->nwords - 1] != 0);
+ Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+ Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
/* Handle cases where either input is NULL */
if (a == NULL)
return NULL;
if (b == NULL)
return a;
+
+#ifdef REALLOCATE_BITMAPSETS
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#endif
+
/* Remove b's bits from a; we need never copy */
if (a->nwords > b->nwords)
{
@@ -1054,12 +1155,25 @@ bms_join(Bitmapset *a, Bitmapset *b)
Bitmapset *other;
int otherlen;
int i;
+#ifdef REALLOCATE_BITMAPSETS
+ Bitmapset *tmp = a;
+#endif
+
+ Assert(a == NULL || IsA(a, Bitmapset));
+ Assert(b == NULL || IsA(b, Bitmapset));
/* Handle cases where either input is NULL */
if (a == NULL)
return b;
if (b == NULL)
return a;
+
+#ifdef REALLOCATE_BITMAPSETS
+ a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords));
+ memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords));
+ pfree(tmp);
+#endif
+
/* Identify shorter and longer input; use longer one as result */
if (a->nwords < b->nwords)
{
@@ -1109,6 +1223,8 @@ bms_next_member(const Bitmapset *a, int prevbit)
int wordnum;
bitmapword mask;
+ Assert(a == NULL || IsA(a, Bitmapset));
+
if (a == NULL)
return -2;
nwords = a->nwords;
@@ -1168,6 +1284,8 @@ bms_prev_member(const Bitmapset *a, int prevbit)
int ushiftbits;
bitmapword mask;
+ Assert(a == NULL || IsA(a, Bitmapset));
+
/*
* If set is NULL or if there are no more bits to the right then we've
* nothing to do.
diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
index 8a6e67a445d..16c383ba7f7 100644
--- a/src/include/pg_config_manual.h
+++ b/src/include/pg_config_manual.h
@@ -335,6 +335,12 @@
*/
/* #define COPY_PARSE_PLAN_TREES */
+/*
+ * Define this to force Bitmapset reallocation on each modification. Helps
+ * to find hangling pointers to Bitmapset's.
+ */
+/* #define REALLOCATE_BITMAPSETS */
+
/*
* Define this to force all parse and plan trees to be passed through
* outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in
--
2.39.3 (Apple Git-145)