@@ -109,6 +109,7 @@ typedef struct InProgressIO
109
109
struct ReadStream
110
110
{
111
111
int16 max_ios ;
112
+ int16 io_combine_limit ;
112
113
int16 ios_in_progress ;
113
114
int16 queue_size ;
114
115
int16 max_pinned_buffers ;
@@ -219,7 +220,7 @@ read_stream_start_pending_read(ReadStream *stream, bool suppress_advice)
219
220
220
221
/* This should only be called with a pending read. */
221
222
Assert (stream -> pending_read_nblocks > 0 );
222
- Assert (stream -> pending_read_nblocks <=io_combine_limit );
223
+ Assert (stream -> pending_read_nblocks <=stream -> io_combine_limit );
223
224
224
225
/* We had better not exceed the pin limit by starting this read. */
225
226
Assert (stream -> pinned_buffers + stream -> pending_read_nblocks <=
@@ -307,7 +308,7 @@ read_stream_look_ahead(ReadStream *stream, bool suppress_advice)
307
308
int16 buffer_index ;
308
309
void * per_buffer_data ;
309
310
310
- if (stream -> pending_read_nblocks == io_combine_limit )
311
+ if (stream -> pending_read_nblocks == stream -> io_combine_limit )
311
312
{
312
313
read_stream_start_pending_read (stream ,suppress_advice );
313
314
suppress_advice = false;
@@ -367,7 +368,7 @@ read_stream_look_ahead(ReadStream *stream, bool suppress_advice)
367
368
* signaled end-of-stream, we start the read immediately.
368
369
*/
369
370
if (stream -> pending_read_nblocks > 0 &&
370
- (stream -> pending_read_nblocks == io_combine_limit ||
371
+ (stream -> pending_read_nblocks == stream -> io_combine_limit ||
371
372
(stream -> pending_read_nblocks == stream -> distance &&
372
373
stream -> pinned_buffers == 0 )||
373
374
stream -> distance == 0 )&&
@@ -396,6 +397,7 @@ read_stream_begin_relation(int flags,
396
397
ReadStream * stream ;
397
398
size_t size ;
398
399
int16 queue_size ;
400
+ int16 queue_overflow ;
399
401
int max_ios ;
400
402
int strategy_pin_limit ;
401
403
uint32 max_pinned_buffers ;
@@ -429,6 +431,14 @@ read_stream_begin_relation(int flags,
429
431
/* Cap to INT16_MAX to avoid overflowing below */
430
432
max_ios = Min (max_ios ,PG_INT16_MAX );
431
433
434
+ /*
435
+ * If starting a multi-block I/O near the end of the queue, we might
436
+ * temporarily need extra space for overflowing buffers before they are
437
+ * moved to regular circular position. This is the maximum extra space we
438
+ * could need.
439
+ */
440
+ queue_overflow = io_combine_limit - 1 ;
441
+
432
442
/*
433
443
* Choose the maximum number of buffers we're prepared to pin. We try to
434
444
* pin fewer if we can, though. We clamp it to at least io_combine_limit
@@ -439,7 +449,7 @@ read_stream_begin_relation(int flags,
439
449
*/
440
450
max_pinned_buffers = Max (max_ios * 4 ,io_combine_limit );
441
451
max_pinned_buffers = Min (max_pinned_buffers ,
442
- PG_INT16_MAX - io_combine_limit - 1 );
452
+ PG_INT16_MAX - queue_overflow - 1 );
443
453
444
454
/* Give the strategy a chance to limit the number of buffers we pin. */
445
455
strategy_pin_limit = GetAccessStrategyPinLimit (strategy );
@@ -465,18 +475,17 @@ read_stream_begin_relation(int flags,
465
475
* one big chunk. Though we have queue_size buffers, we want to be able
466
476
* to assume that all the buffers for a single read are contiguous (i.e.
467
477
* don't wrap around halfway through), so we allow temporary overflows of
468
- * up to the maximum possible read size by allocating an extra
469
- * io_combine_limit - 1 elements.
478
+ * up to the maximum possible overflow size.
470
479
*/
471
480
size = offsetof(ReadStream ,buffers );
472
- size += sizeof (Buffer )* (queue_size + io_combine_limit - 1 );
481
+ size += sizeof (Buffer )* (queue_size + queue_overflow );
473
482
size += sizeof (InProgressIO )* Max (1 ,max_ios );
474
483
size += per_buffer_data_size * queue_size ;
475
484
size += MAXIMUM_ALIGNOF * 2 ;
476
485
stream = (ReadStream * )palloc (size );
477
486
memset (stream ,0 , offsetof(ReadStream ,buffers ));
478
487
stream -> ios = (InProgressIO * )
479
- MAXALIGN (& stream -> buffers [queue_size + io_combine_limit - 1 ]);
488
+ MAXALIGN (& stream -> buffers [queue_size + queue_overflow ]);
480
489
if (per_buffer_data_size > 0 )
481
490
stream -> per_buffer_data = (void * )
482
491
MAXALIGN (& stream -> ios [Max (1 ,max_ios )]);
@@ -503,7 +512,14 @@ read_stream_begin_relation(int flags,
503
512
if (max_ios == 0 )
504
513
max_ios = 1 ;
505
514
515
+ /*
516
+ * Capture stable values for these two GUC-derived numbers for the
517
+ * lifetime of this stream, so we don't have to worry about the GUCs
518
+ * changing underneath us beyond this point.
519
+ */
506
520
stream -> max_ios = max_ios ;
521
+ stream -> io_combine_limit = io_combine_limit ;
522
+
507
523
stream -> per_buffer_data_size = per_buffer_data_size ;
508
524
stream -> max_pinned_buffers = max_pinned_buffers ;
509
525
stream -> queue_size = queue_size ;
@@ -517,7 +533,7 @@ read_stream_begin_relation(int flags,
517
533
* doing full io_combine_limit sized reads (behavior B).
518
534
*/
519
535
if (flags & READ_STREAM_FULL )
520
- stream -> distance = Min (max_pinned_buffers ,io_combine_limit );
536
+ stream -> distance = Min (max_pinned_buffers ,stream -> io_combine_limit );
521
537
else
522
538
stream -> distance = 1 ;
523
539
@@ -683,14 +699,14 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
683
699
else
684
700
{
685
701
/* No advice; move towards io_combine_limit (behavior B). */
686
- if (stream -> distance > io_combine_limit )
702
+ if (stream -> distance > stream -> io_combine_limit )
687
703
{
688
704
stream -> distance -- ;
689
705
}
690
706
else
691
707
{
692
708
distance = stream -> distance * 2 ;
693
- distance = Min (distance ,io_combine_limit );
709
+ distance = Min (distance ,stream -> io_combine_limit );
694
710
distance = Min (distance ,stream -> max_pinned_buffers );
695
711
stream -> distance = distance ;
696
712
}