25
25
#include "miscadmin.h"
26
26
#include "storage/bufmgr.h"
27
27
#include "storage/procarray.h"
28
+ #include "storage/read_stream.h"
28
29
#include "utils/builtins.h"
29
30
#include "utils/fmgroids.h"
30
31
#include "utils/rel.h"
@@ -185,6 +186,43 @@ static XidBoundsViolation get_xid_status(TransactionId xid,
185
186
HeapCheckContext * ctx ,
186
187
XidCommitStatus * status );
187
188
189
+ typedef struct heapamcheck_rs_perblock_data
190
+ {
191
+ BlockRangeReadStreamPrivate range ;
192
+ SkipPages skip_option ;
193
+ Relation rel ;
194
+ Buffer * vmbuffer ;
195
+ } heapamcheck_rs_perblock_data ;
196
+
197
+ static BlockNumber
198
+ heapam_read_stream_next_block (ReadStream * stream ,
199
+ void * callback_private_data ,
200
+ void * per_buffer_data )
201
+ {
202
+ heapamcheck_rs_perblock_data * p = callback_private_data ;
203
+
204
+ for (BlockNumber i ; (i = p -> range .current_blocknum ++ ) < p -> range .last_exclusive ;)
205
+ {
206
+ int32 mapbits = visibilitymap_get_status (p -> rel , i , p -> vmbuffer );
207
+
208
+ if (p -> skip_option == SKIP_PAGES_ALL_FROZEN )
209
+ {
210
+ if ((mapbits & VISIBILITYMAP_ALL_FROZEN ) != 0 )
211
+ continue ;
212
+ }
213
+
214
+ if (p -> skip_option == SKIP_PAGES_ALL_VISIBLE )
215
+ {
216
+ if ((mapbits & VISIBILITYMAP_ALL_VISIBLE ) != 0 )
217
+ continue ;
218
+ }
219
+
220
+ return i ;
221
+ }
222
+
223
+ return InvalidBlockNumber ;
224
+ }
225
+
188
226
/*
189
227
* Scan and report corruption in heap pages, optionally reconciling toasted
190
228
* attributes with entries in the associated toast table. Intended to be
@@ -231,6 +269,11 @@ verify_heapam(PG_FUNCTION_ARGS)
231
269
BlockNumber last_block ;
232
270
BlockNumber nblocks ;
233
271
const char * skip ;
272
+ ReadStream * stream ;
273
+ int read_stream_flags ;
274
+ ReadStreamBlockNumberCB cb ;
275
+ heapamcheck_rs_perblock_data rsdata ;
276
+ void * stream_callback_private ;
234
277
235
278
/* Check supplied arguments */
236
279
if (PG_ARGISNULL (0 ))
@@ -404,7 +447,34 @@ verify_heapam(PG_FUNCTION_ARGS)
404
447
if (TransactionIdIsNormal (ctx .relfrozenxid ))
405
448
ctx .oldest_xid = ctx .relfrozenxid ;
406
449
407
- for (ctx .blkno = first_block ; ctx .blkno <= last_block ; ctx .blkno ++ )
450
+ rsdata .range .current_blocknum = first_block ;
451
+ rsdata .range .last_exclusive = last_block + 1 ;
452
+ rsdata .skip_option = skip_option ;
453
+ rsdata .rel = ctx .rel ;
454
+ rsdata .vmbuffer = & vmbuffer ;
455
+
456
+ if (skip_option == SKIP_PAGES_NONE )
457
+ {
458
+ cb = block_range_read_stream_cb ;
459
+ read_stream_flags = READ_STREAM_SEQUENTIAL | READ_STREAM_FULL ;
460
+ stream_callback_private = & rsdata .range ;
461
+ }
462
+ else
463
+ {
464
+ cb = heapam_read_stream_next_block ;
465
+ read_stream_flags = READ_STREAM_DEFAULT ;
466
+ stream_callback_private = & rsdata ;
467
+ }
468
+
469
+ stream = read_stream_begin_relation (read_stream_flags ,
470
+ ctx .bstrategy ,
471
+ ctx .rel ,
472
+ MAIN_FORKNUM ,
473
+ cb ,
474
+ stream_callback_private ,
475
+ 0 );
476
+
477
+ while ((ctx .buffer = read_stream_next_buffer (stream , NULL )) != InvalidBuffer )
408
478
{
409
479
OffsetNumber maxoff ;
410
480
OffsetNumber predecessor [MaxOffsetNumber ];
@@ -417,30 +487,11 @@ verify_heapam(PG_FUNCTION_ARGS)
417
487
418
488
memset (predecessor , 0 , sizeof (OffsetNumber ) * MaxOffsetNumber );
419
489
420
- /* Optionally skip over all-frozen or all-visible blocks */
421
- if (skip_option != SKIP_PAGES_NONE )
422
- {
423
- int32 mapbits ;
424
-
425
- mapbits = (int32 ) visibilitymap_get_status (ctx .rel , ctx .blkno ,
426
- & vmbuffer );
427
- if (skip_option == SKIP_PAGES_ALL_FROZEN )
428
- {
429
- if ((mapbits & VISIBILITYMAP_ALL_FROZEN ) != 0 )
430
- continue ;
431
- }
432
-
433
- if (skip_option == SKIP_PAGES_ALL_VISIBLE )
434
- {
435
- if ((mapbits & VISIBILITYMAP_ALL_VISIBLE ) != 0 )
436
- continue ;
437
- }
438
- }
439
-
440
- /* Read and lock the next page. */
441
- ctx .buffer = ReadBufferExtended (ctx .rel , MAIN_FORKNUM , ctx .blkno ,
442
- RBM_NORMAL , ctx .bstrategy );
490
+ /* Lock the next page. */
491
+ Assert (BufferIsValid (ctx .buffer ));
443
492
LockBuffer (ctx .buffer , BUFFER_LOCK_SHARE );
493
+
494
+ ctx .blkno = BufferGetBlockNumber (ctx .buffer );
444
495
ctx .page = BufferGetPage (ctx .buffer );
445
496
446
497
/* Perform tuple checks */
@@ -798,6 +849,9 @@ verify_heapam(PG_FUNCTION_ARGS)
798
849
if (on_error_stop && ctx .is_corrupt )
799
850
break ;
800
851
}
852
+ /* Ensure that the stream is completely read */
853
+ Assert (read_stream_next_buffer (stream , NULL ) == InvalidBuffer );
854
+ read_stream_end (stream );
801
855
802
856
if (vmbuffer != InvalidBuffer )
803
857
ReleaseBuffer (vmbuffer );
0 commit comments