Skip to content

Commit

Permalink
[#22071] YSQL: Fix Bitmap Scan Postmaster Crash
Browse files Browse the repository at this point in the history
Summary:
D34122 / 7b418b8 introduced a fix for Bitmap Scan pushdown on primary indexes for colocated tables. This inadvertently caused a TServer crash for Bitmap
Scan pushdown on secondary indexes on text columns on colocated tables. When the tserver crashes, the Postmaster exits normally

The check added in D34122 classified secondary indexes as primary indexes too - which worked fine for integer columns, but not for text columns. That's why
this issue wasn't caught by the tests - because there were no colocated text tests.

Updating the `is_primary` check allows for the pushdown expressions to be applied as expected to either the main table or the remote filter.

Also, I created `relation` and `index` variables to increase the readability of `nodeYbBitmapIndexScan`.
Jira: DB-10992

Test Plan:

```
./yb_build.sh --java-test 'org.yb.pgsql.TestPgRegressYbBitmapScans'
```

Updated the bitmap scan regression test to include text columns on the colocated table.

Reviewers: tnayak, amartsinchyk

Reviewed By: tnayak, amartsinchyk

Subscribers: smishra, yql

Differential Revision: https://phorge.dev.yugabyte.com/D34397
  • Loading branch information
timothy-e committed May 7, 2024
1 parent de9fd5d commit b571eda
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 98 deletions.
24 changes: 13 additions & 11 deletions src/postgres/src/backend/executor/nodeYbBitmapIndexscan.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ ExecInitYbBitmapIndexScan(YbBitmapIndexScan *node, EState *estate, int eflags)
{
YbBitmapIndexScanState *indexstate;
bool relistarget;
Relation index;
Relation relation;

/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
Expand Down Expand Up @@ -275,19 +277,22 @@ ExecInitYbBitmapIndexScan(YbBitmapIndexScan *node, EState *estate, int eflags)
return indexstate;

/*
* Open the index relation.
* Open the index and main table relations. Unlike Postgres, Yugabyte needs
* both to properly construct the request.
*
* If the parent table is one of the target relations of the query, then
* InitPlan already opened and write-locked the index, so we can avoid
* taking another lock here. Otherwise we need a normal reader's lock.
*/
relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
indexstate->biss_RelationDesc = index_open(node->indexid,
relistarget ? NoLock : AccessShareLock);
index = index_open(node->indexid, relistarget ? NoLock : AccessShareLock);
relation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
Assert(IsYBRelation(index));

/*
* Initialize index-specific scan state
*/
indexstate->biss_RelationDesc = index;
indexstate->biss_RuntimeKeysReady = false;
indexstate->biss_RuntimeKeys = NULL;
indexstate->biss_NumRuntimeKeys = 0;
Expand Down Expand Up @@ -330,21 +335,18 @@ ExecInitYbBitmapIndexScan(YbBitmapIndexScan *node, EState *estate, int eflags)
* Initialize scan descriptor.
*/
indexstate->biss_ScanDesc =
index_beginscan_bitmap(indexstate->biss_RelationDesc,
index_beginscan_bitmap(index,
estate->es_snapshot,
indexstate->biss_NumScanKeys);

if (IsYBRelation(indexstate->biss_RelationDesc))
indexstate->ss.ss_currentRelation =
ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);

indexstate->biss_ScanDesc->heapRelation =
indexstate->ss.ss_currentRelation;
indexstate->ss.ss_currentRelation = relation;
indexstate->biss_ScanDesc->heapRelation = relation;
indexstate->biss_ScanDesc->yb_exec_params = &estate->yb_exec_params;
indexstate->biss_ScanDesc->fetch_ybctids_only = true;

const bool is_colocated = YbGetTableProperties(indexstate->ss.ss_currentRelation)->is_colocated;
const bool is_primary = indexstate->ss.ss_currentRelation->rd_index == NULL;
const bool is_colocated = YbGetTableProperties(relation)->is_colocated;
const bool is_primary = relation->rd_pkindex == index->rd_id;

/* primary keys on colocated indexes don't have a secondary index in their request */
if (is_colocated && is_primary)
Expand Down
185 changes: 112 additions & 73 deletions src/postgres/src/test/regress/expected/yb_bitmap_scans.out
Original file line number Diff line number Diff line change
Expand Up @@ -1455,11 +1455,12 @@ CREATE DATABASE colo WITH colocation = true;
SET yb_explain_hide_non_deterministic_fields = true;
SET enable_bitmapscan = true;
SET yb_enable_bitmapscan = true;
CREATE TABLE pk_colo (k INT PRIMARY KEY, a INT);
CREATE TABLE pk_colo (k INT PRIMARY KEY, a INT, v varchar);
CREATE INDEX ON pk_colo(a ASC);
INSERT INTO pk_colo SELECT i, i FROM generate_series(1, 1000) i;
CREATE INDEX ON pk_colo(v ASC);
INSERT INTO pk_colo SELECT i, i, i::text FROM generate_series(1, 1000) i;
/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, DIST, COSTS OFF)
SELECT * FROM pk_colo WHERE k = 123 OR a = 123;
SELECT * FROM pk_colo WHERE k = 123 OR a = 123 OR v = '123';
QUERY PLAN
------------------------------------------------------------------------
YB Bitmap Table Scan on pk_colo (actual rows=1 loops=1)
Expand All @@ -1475,28 +1476,33 @@ SELECT * FROM pk_colo WHERE k = 123 OR a = 123;
Storage Table Rows Scanned: 1
Storage Index Read Requests: 1
Storage Index Rows Scanned: 1
Storage Read Requests: 3
Storage Rows Scanned: 4
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=1 loops=1)
Index Cond: ((v)::text = '123'::text)
Storage Table Rows Scanned: 1
Storage Index Read Requests: 1
Storage Index Rows Scanned: 1
Storage Read Requests: 4
Storage Rows Scanned: 6
Storage Write Requests: 0
Storage Flush Requests: 0
(17 rows)
(22 rows)

/*+ BitmapScan(pk_colo) */
SELECT * FROM pk_colo WHERE k = 123 OR a = 123;
k | a
-----+-----
123 | 123
SELECT * FROM pk_colo WHERE k = 123 OR a = 123 OR v = '123';
k | a | v
-----+-----+-----
123 | 123 | 123
(1 row)

/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, DIST, COSTS OFF)
SELECT * FROM pk_colo WHERE (k < 10 AND k % 2 = 1) OR (a > 990 AND a % 2 = 1) ORDER BY k;
QUERY PLAN
-----------------------------------------------------------------------------------------
SELECT * FROM pk_colo WHERE (k < 10 AND k % 2 = 1) OR (a > 990 AND a % 2 = 1) OR (v LIKE '999%' AND v LIKE '%5') ORDER BY k;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (actual rows=10 loops=1)
Sort Key: k
Sort Method: quicksort
-> YB Bitmap Table Scan on pk_colo (actual rows=10 loops=1)
Storage Filter: (((k < 10) AND ((k % 2) = 1)) OR ((a > 990) AND ((a % 2) = 1)))
Storage Filter: (((k < 10) AND ((k % 2) = 1)) OR ((a > 990) AND ((a % 2) = 1)) OR (((v)::text ~~ '999%'::text) AND ((v)::text ~~ '%5'::text)))
Storage Table Read Requests: 1
Storage Table Rows Scanned: 10
-> BitmapOr (actual rows=10 loops=1)
Expand All @@ -1511,39 +1517,45 @@ SELECT * FROM pk_colo WHERE (k < 10 AND k % 2 = 1) OR (a > 990 AND a % 2 = 1) OR
Storage Table Rows Scanned: 10
Storage Index Read Requests: 1
Storage Index Rows Scanned: 10
Storage Read Requests: 3
Storage Rows Scanned: 39
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=0 loops=1)
Index Cond: (((v)::text >= '999'::text) AND ((v)::text < '99:'::text))
Storage Index Filter: ((v)::text ~~ '%5'::text)
Storage Table Rows Scanned: 1
Storage Index Read Requests: 1
Storage Index Rows Scanned: 1
Storage Read Requests: 4
Storage Rows Scanned: 41
Storage Write Requests: 0
Storage Flush Requests: 0
(23 rows)
(29 rows)

/*+ BitmapScan(pk_colo) */
SELECT * FROM pk_colo WHERE (k < 10 AND k % 2 = 1) OR (a > 990 AND a % 2 = 1) ORDER BY k;
k | a
-----+-----
1 | 1
3 | 3
5 | 5
7 | 7
9 | 9
991 | 991
993 | 993
995 | 995
997 | 997
999 | 999
SELECT * FROM pk_colo WHERE (k < 10 AND k % 2 = 1) OR (a > 990 AND a % 2 = 1) OR (v LIKE '999%' AND v LIKE '%5') ORDER BY k;
k | a | v
-----+-----+-----
1 | 1 | 1
3 | 3 | 3
5 | 5 | 5
7 | 7 | 7
9 | 9 | 9
991 | 991 | 991
993 | 993 | 993
995 | 995 | 995
997 | 997 | 997
999 | 999 | 999
(10 rows)

/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, DIST, COSTS OFF)
SELECT * FROM pk_colo WHERE k < 5 OR a BETWEEN 7 AND 8 ORDER BY k;
SELECT * FROM pk_colo WHERE k < 5 OR (a BETWEEN 7 AND 8) OR v < '11' ORDER BY k;
QUERY PLAN
------------------------------------------------------------------------------
Sort (actual rows=6 loops=1)
-------------------------------------------------------------------------------
Sort (actual rows=18 loops=1)
Sort Key: k
Sort Method: quicksort
-> YB Bitmap Table Scan on pk_colo (actual rows=6 loops=1)
-> YB Bitmap Table Scan on pk_colo (actual rows=18 loops=1)
Storage Table Read Requests: 1
Storage Table Rows Scanned: 6
-> BitmapOr (actual rows=6 loops=1)
Storage Table Rows Scanned: 18
-> BitmapOr (actual rows=18 loops=1)
-> Bitmap Index Scan on pk_colo_pkey (actual rows=4 loops=1)
Index Cond: (k < 5)
Storage Table Read Requests: 1
Expand All @@ -1553,35 +1565,52 @@ SELECT * FROM pk_colo WHERE k < 5 OR a BETWEEN 7 AND 8 ORDER BY k;
Storage Table Rows Scanned: 2
Storage Index Read Requests: 1
Storage Index Rows Scanned: 2
Storage Read Requests: 3
Storage Rows Scanned: 14
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=13 loops=1)
Index Cond: ((v)::text < '11'::text)
Storage Table Rows Scanned: 13
Storage Index Read Requests: 1
Storage Index Rows Scanned: 13
Storage Read Requests: 4
Storage Rows Scanned: 52
Storage Write Requests: 0
Storage Flush Requests: 0
(20 rows)
(25 rows)

/*+ BitmapScan(pk_colo) */
SELECT * FROM pk_colo WHERE k < 5 OR a BETWEEN 7 AND 8 ORDER BY k;
k | a
---+---
1 | 1
2 | 2
3 | 3
4 | 4
7 | 7
8 | 8
(6 rows)
SELECT * FROM pk_colo WHERE k < 5 OR (a BETWEEN 7 AND 8) OR v < '11' ORDER BY k;
k | a | v
------+------+------
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
4 | 4 | 4
7 | 7 | 7
8 | 8 | 8
10 | 10 | 10
100 | 100 | 100
101 | 101 | 101
102 | 102 | 102
103 | 103 | 103
104 | 104 | 104
105 | 105 | 105
106 | 106 | 106
107 | 107 | 107
108 | 108 | 108
109 | 109 | 109
1000 | 1000 | 1000
(18 rows)

/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, DIST, COSTS OFF)
SELECT * FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) ORDER BY k;
SELECT * FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) OR v IN ('122', '125') ORDER BY k;
QUERY PLAN
------------------------------------------------------------------------------
Sort (actual rows=3 loops=1)
Sort (actual rows=4 loops=1)
Sort Key: k
Sort Method: quicksort
-> YB Bitmap Table Scan on pk_colo (actual rows=3 loops=1)
-> YB Bitmap Table Scan on pk_colo (actual rows=4 loops=1)
Storage Table Read Requests: 1
Storage Table Rows Scanned: 3
-> BitmapOr (actual rows=3 loops=1)
Storage Table Rows Scanned: 4
-> BitmapOr (actual rows=4 loops=1)
-> Bitmap Index Scan on pk_colo_pkey (actual rows=2 loops=1)
Index Cond: (k = ANY ('{123,124}'::integer[]))
Storage Table Read Requests: 1
Expand All @@ -1591,45 +1620,53 @@ SELECT * FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) ORDER BY k;
Storage Table Rows Scanned: 2
Storage Index Read Requests: 1
Storage Index Rows Scanned: 2
Storage Read Requests: 3
Storage Rows Scanned: 9
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=2 loops=1)
Index Cond: ((v)::text = ANY ('{122,125}'::text[]))
Storage Table Rows Scanned: 2
Storage Index Read Requests: 1
Storage Index Rows Scanned: 2
Storage Read Requests: 4
Storage Rows Scanned: 14
Storage Write Requests: 0
Storage Flush Requests: 0
(20 rows)
(25 rows)

/*+ BitmapScan(pk_colo) */
SELECT * FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) ORDER BY k;
k | a
-----+-----
122 | 122
123 | 123
124 | 124
(3 rows)
SELECT * FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) OR v IN ('122', '125') ORDER BY k;
k | a | v
-----+-----+-----
122 | 122 | 122
123 | 123 | 123
124 | 124 | 124
125 | 125 | 125
(4 rows)

-- test count
/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, COSTS OFF)
SELECT COUNT(*) FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123);
SELECT COUNT(*) FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) OR v IN ('122', '125');
QUERY PLAN
------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> YB Bitmap Table Scan on pk_colo (actual rows=3 loops=1)
-> BitmapOr (actual rows=3 loops=1)
-> YB Bitmap Table Scan on pk_colo (actual rows=4 loops=1)
-> BitmapOr (actual rows=4 loops=1)
-> Bitmap Index Scan on pk_colo_pkey (actual rows=2 loops=1)
Index Cond: (k = ANY ('{123,124}'::integer[]))
-> Bitmap Index Scan on pk_colo_a_idx (actual rows=2 loops=1)
Index Cond: (a = ANY ('{122,123}'::integer[]))
(7 rows)
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=2 loops=1)
Index Cond: ((v)::text = ANY ('{122,125}'::text[]))
(9 rows)

/*+ BitmapScan(pk_colo) */
SELECT COUNT(*) FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123);
SELECT COUNT(*) FROM pk_colo WHERE k IN (123, 124) OR a IN (122, 123) OR v IN ('122', '125');
count
-------
3
4
(1 row)

-- test non-existent results
/*+ BitmapScan(pk_colo) */ EXPLAIN (ANALYZE, COSTS OFF)
SELECT COUNT(*) FROM pk_colo WHERE k = 2000 OR a < 0;
SELECT COUNT(*) FROM pk_colo WHERE k = 2000 OR a < 0 OR v = 'nonexistent';
QUERY PLAN
------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
Expand All @@ -1639,10 +1676,12 @@ SELECT COUNT(*) FROM pk_colo WHERE k = 2000 OR a < 0;
Index Cond: (k = 2000)
-> Bitmap Index Scan on pk_colo_a_idx (actual rows=0 loops=1)
Index Cond: (a < 0)
(7 rows)
-> Bitmap Index Scan on pk_colo_v_idx (actual rows=0 loops=1)
Index Cond: ((v)::text = 'nonexistent'::text)
(9 rows)

/*+ BitmapScan(pk_colo) */
SELECT COUNT(*) FROM pk_colo WHERE k = 2000 OR a < 0;
SELECT COUNT(*) FROM pk_colo WHERE k = 2000 OR a < 0 OR v = 'nonexistent';
count
-------
0
Expand Down

0 comments on commit b571eda

Please sign in to comment.