=== Applying patches on top of PostgreSQL commit ID 53a49365052026907afff7613929710d1e7f0da0 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sat Feb 1 04:50:30 UTC 2025 On branch cf/5448 nothing to commit, working tree clean === applying patch ./v3-0001-Remove-BitmapScan-s-skip_fetch-optimization.patch Applied patch to 'src/include/access/heapam.h' with conflicts. Applied patch to 'src/include/access/tableam.h' cleanly. Applied patch to 'src/backend/access/heap/heapam.c' with conflicts. Applied patch to 'src/backend/access/heap/heapam_handler.c' with conflicts. Applied patch to 'src/backend/executor/nodeBitmapHeapscan.c' with conflicts. U src/backend/access/heap/heapam.c U src/backend/access/heap/heapam_handler.c U src/backend/executor/nodeBitmapHeapscan.c U src/include/access/heapam.h diff --cc src/backend/access/heap/heapam.c index ea0a12b39a,905dd9d04a..0000000000 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@@ -1182,24 -1171,6 +1182,27 @@@ heap_rescan(TableScanDesc sscan, ScanKe if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); ++<<<<<<< ours + if (scan->rs_base.rs_flags & SO_TYPE_BITMAPSCAN) + { + BitmapHeapScanDesc bscan = (BitmapHeapScanDesc) scan; + + /* + * Reset empty_tuples_pending, a field only used by bitmap heap scan, + * to avoid incorrectly emitting NULL-filled tuples from a previous + * scan on rescan. + */ + bscan->rs_empty_tuples_pending = 0; + + if (BufferIsValid(bscan->rs_vmbuffer)) + { + ReleaseBuffer(bscan->rs_vmbuffer); + bscan->rs_vmbuffer = InvalidBuffer; + } + } + ++======= ++>>>>>>> theirs /* * The read stream is reset on rescan. This must be done before * initscan(), as some state referred to by read_stream_reset() is reset @@@ -1227,15 -1198,6 +1230,18 @@@ heap_endscan(TableScanDesc sscan if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); ++<<<<<<< ours + if (scan->rs_base.rs_flags & SO_TYPE_BITMAPSCAN) + { + BitmapHeapScanDesc bscan = (BitmapHeapScanDesc) sscan; + + bscan->rs_empty_tuples_pending = 0; + if (BufferIsValid(bscan->rs_vmbuffer)) + ReleaseBuffer(bscan->rs_vmbuffer); + } + ++======= ++>>>>>>> theirs /* * Must free the read stream before freeing the BufferAccessStrategy. */ diff --cc src/backend/access/heap/heapam_handler.c index a4003cf59e,0ea4f02979..0000000000 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@@ -2158,24 -2155,6 +2158,27 @@@ heapam_scan_bitmap_next_block(TableScan *blockno = tbmres->blockno; *recheck = tbmres->recheck; ++<<<<<<< ours + /* + * We can skip fetching the heap page if we don't need any fields from the + * heap, the bitmap entries don't need rechecking, and all tuples on the + * page are visible to our transaction. + */ + if (!(scan->rs_flags & SO_NEED_TUPLES) && + !tbmres->recheck && + VM_ALL_VISIBLE(scan->rs_rd, tbmres->blockno, &bscan->rs_vmbuffer)) + { + /* can't be lossy in the skip_fetch case */ + Assert(tbmres->ntuples >= 0); + Assert(bscan->rs_empty_tuples_pending >= 0); + + bscan->rs_empty_tuples_pending += tbmres->ntuples; + + return true; + } + ++======= ++>>>>>>> theirs block = tbmres->blockno; /* @@@ -2291,16 -2269,6 +2294,19 @@@ heapam_scan_bitmap_next_tuple(TableScan Page page; ItemId lp; ++<<<<<<< ours + if (bscan->rs_empty_tuples_pending > 0) + { + /* + * If we don't have to fetch the tuple, just return nulls. + */ + ExecStoreAllNullTuple(slot); + bscan->rs_empty_tuples_pending--; + return true; + } + ++======= ++>>>>>>> theirs /* * Out of range? If so, nothing more to look at on this page */ diff --cc src/backend/executor/nodeBitmapHeapscan.c index be0d24d901,e5d7fab4db..0000000000 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@@ -189,8 -87,88 +189,85 @@@ BitmapHeapNext(BitmapHeapScanState *nod */ if (!node->initialized) { ++<<<<<<< ours + BitmapTableScanSetup(node); + scan = node->ss.ss_currentScanDesc; ++======= + TBMIterator tbmiterator; + + if (!pstate) + { + tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); + + if (!tbm || !IsA(tbm, TIDBitmap)) + elog(ERROR, "unrecognized result from subplan"); + + node->tbm = tbm; + } + else if (BitmapShouldInitializeSharedState(pstate)) + { + /* + * The leader will immediately come out of the function, but + * others will be blocked until leader populates the TBM and wakes + * them up. + */ + tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); + if (!tbm || !IsA(tbm, TIDBitmap)) + elog(ERROR, "unrecognized result from subplan"); + + node->tbm = tbm; + + /* + * Prepare to iterate over the TBM. This will return the + * dsa_pointer of the iterator state which will be used by + * multiple processes to iterate jointly. + */ + pstate->tbmiterator = tbm_prepare_shared_iterate(tbm); + + #ifdef USE_PREFETCH + if (node->prefetch_maximum > 0) + { + pstate->prefetch_iterator = + tbm_prepare_shared_iterate(tbm); + } + #endif /* USE_PREFETCH */ + + /* We have initialized the shared state so wake up others. */ + BitmapDoneInitializingSharedState(pstate); + } + + tbmiterator = tbm_begin_iterate(tbm, dsa, + pstate ? + pstate->tbmiterator : + InvalidDsaPointer); + + #ifdef USE_PREFETCH + if (node->prefetch_maximum > 0) + node->prefetch_iterator = + tbm_begin_iterate(tbm, dsa, + pstate ? + pstate->prefetch_iterator : + InvalidDsaPointer); + #endif /* USE_PREFETCH */ + + /* + * If this is the first scan of the underlying table, create the table + * scan descriptor and begin the scan. + */ + if (!scan) + { + scan = table_beginscan_bm(node->ss.ss_currentRelation, + node->ss.ps.state->es_snapshot, + 0, + NULL); + + node->ss.ss_currentScanDesc = scan; + } + + scan->st.rs_tbmiterator = tbmiterator; + node->initialized = true; + ++>>>>>>> theirs goto new_page; } diff --cc src/include/access/heapam.h index 1640d9c32f,84a1f30aec..0000000000 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@@ -108,14 -97,16 +108,17 @@@ typedef struct BitmapHeapScanDescDat * optimization. Bitmap scans needing no fields from the heap may skip * fetching an all visible block, instead using the number of tuples per * block reported by the bitmap to determine how many NULL-filled tuples - * to return. + * to return. They are common to parallel and serial BitmapHeapScans */ - int rs_empty_tuples_pending; ++<<<<<<< ours - /* these fields only used in page-at-a-time mode and for bitmap scans */ - uint32 rs_cindex; /* current tuple's index in vistuples */ - uint32 rs_ntuples; /* number of visible tuples on page */ - OffsetNumber rs_vistuples[MaxHeapTuplesPerPage]; /* their offsets */ -} HeapScanDescData; -typedef struct HeapScanDescData *HeapScanDesc; + /* page of VM containing info for current block */ + Buffer rs_vmbuffer; ++======= ++>>>>>>> theirs + int rs_empty_tuples_pending; +} BitmapHeapScanDescData; +typedef struct BitmapHeapScanDescData *BitmapHeapScanDesc; /* * Descriptor for fetches from heap via an index.