@@ -143,10 +143,11 @@ struct shm_mq_handle
143
143
};
144
144
145
145
static void shm_mq_detach_internal (shm_mq * mq );
146
- static shm_mq_result shm_mq_send_bytes (shm_mq_handle * mq , Size nbytes ,
146
+ static shm_mq_result shm_mq_send_bytes (shm_mq_handle * mqh , Size nbytes ,
147
147
const void * data , bool nowait , Size * bytes_written );
148
- static shm_mq_result shm_mq_receive_bytes (shm_mq * mq , Size bytes_needed ,
149
- bool nowait , Size * nbytesp , void * * datap );
148
+ static shm_mq_result shm_mq_receive_bytes (shm_mq_handle * mqh ,
149
+ Size bytes_needed , bool nowait , Size * nbytesp ,
150
+ void * * datap );
150
151
static bool shm_mq_counterparty_gone (shm_mq * mq ,
151
152
BackgroundWorkerHandle * handle );
152
153
static bool shm_mq_wait_internal (shm_mq * mq , PGPROC * * ptr ,
@@ -582,8 +583,14 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
582
583
mqh -> mqh_counterparty_attached = true;
583
584
}
584
585
585
- /* Consume any zero-copy data from previous receive operation. */
586
- if (mqh -> mqh_consume_pending > 0 )
586
+ /*
587
+ * If we've consumed an amount of data greater than 1/4th of the ring
588
+ * size, mark it consumed in shared memory. We try to avoid doing this
589
+ * unnecessarily when only a small amount of data has been consumed,
590
+ * because SetLatch() is fairly expensive and we don't want to do it too
591
+ * often.
592
+ */
593
+ if (mqh -> mqh_consume_pending > mq -> mq_ring_size / 4 )
587
594
{
588
595
shm_mq_inc_bytes_read (mq , mqh -> mqh_consume_pending );
589
596
mqh -> mqh_consume_pending = 0 ;
@@ -594,7 +601,7 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
594
601
{
595
602
/* Try to receive the message length word. */
596
603
Assert (mqh -> mqh_partial_bytes < sizeof (Size ));
597
- res = shm_mq_receive_bytes (mq , sizeof (Size ) - mqh -> mqh_partial_bytes ,
604
+ res = shm_mq_receive_bytes (mqh , sizeof (Size ) - mqh -> mqh_partial_bytes ,
598
605
nowait , & rb , & rawdata );
599
606
if (res != SHM_MQ_SUCCESS )
600
607
return res ;
@@ -614,13 +621,7 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
614
621
needed = MAXALIGN (sizeof (Size )) + MAXALIGN (nbytes );
615
622
if (rb >= needed )
616
623
{
617
- /*
618
- * Technically, we could consume the message length
619
- * information at this point, but the extra write to shared
620
- * memory wouldn't be free and in most cases we would reap no
621
- * benefit.
622
- */
623
- mqh -> mqh_consume_pending = needed ;
624
+ mqh -> mqh_consume_pending += needed ;
624
625
* nbytesp = nbytes ;
625
626
* datap = ((char * ) rawdata ) + MAXALIGN (sizeof (Size ));
626
627
return SHM_MQ_SUCCESS ;
@@ -632,7 +633,7 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
632
633
*/
633
634
mqh -> mqh_expected_bytes = nbytes ;
634
635
mqh -> mqh_length_word_complete = true;
635
- shm_mq_inc_bytes_read ( mq , MAXALIGN (sizeof (Size ) ));
636
+ mqh -> mqh_consume_pending += MAXALIGN (sizeof (Size ));
636
637
rb -= MAXALIGN (sizeof (Size ));
637
638
}
638
639
else
@@ -651,15 +652,15 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
651
652
}
652
653
Assert (mqh -> mqh_buflen >= sizeof (Size ));
653
654
654
- /* Copy and consume partial length word. */
655
+ /* Copy partial length word; remember to consume it . */
655
656
if (mqh -> mqh_partial_bytes + rb > sizeof (Size ))
656
657
lengthbytes = sizeof (Size ) - mqh -> mqh_partial_bytes ;
657
658
else
658
659
lengthbytes = rb ;
659
660
memcpy (& mqh -> mqh_buffer [mqh -> mqh_partial_bytes ], rawdata ,
660
661
lengthbytes );
661
662
mqh -> mqh_partial_bytes += lengthbytes ;
662
- shm_mq_inc_bytes_read ( mq , MAXALIGN (lengthbytes ) );
663
+ mqh -> mqh_consume_pending += MAXALIGN (lengthbytes );
663
664
rb -= lengthbytes ;
664
665
665
666
/* If we now have the whole word, we're ready to read payload. */
@@ -681,13 +682,13 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
681
682
* we need not copy the data and can return a pointer directly into
682
683
* shared memory.
683
684
*/
684
- res = shm_mq_receive_bytes (mq , nbytes , nowait , & rb , & rawdata );
685
+ res = shm_mq_receive_bytes (mqh , nbytes , nowait , & rb , & rawdata );
685
686
if (res != SHM_MQ_SUCCESS )
686
687
return res ;
687
688
if (rb >= nbytes )
688
689
{
689
690
mqh -> mqh_length_word_complete = false;
690
- mqh -> mqh_consume_pending = MAXALIGN (nbytes );
691
+ mqh -> mqh_consume_pending + = MAXALIGN (nbytes );
691
692
* nbytesp = nbytes ;
692
693
* datap = rawdata ;
693
694
return SHM_MQ_SUCCESS ;
@@ -727,21 +728,21 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
727
728
mqh -> mqh_partial_bytes += rb ;
728
729
729
730
/*
730
- * Update count of bytes read, with alignment padding. Note that this
731
- * will never actually insert any padding except at the end of a
732
- * message, because the buffer size is a multiple of MAXIMUM_ALIGNOF,
733
- * and each read and write is as well.
731
+ * Update count of bytes that can be consumed, accounting for
732
+ * alignment padding. Note that this will never actually insert any
733
+ * padding except at the end of a message, because the buffer size is
734
+ * a multiple of MAXIMUM_ALIGNOF, and each read and write is as well.
734
735
*/
735
736
Assert (mqh -> mqh_partial_bytes == nbytes || rb == MAXALIGN (rb ));
736
- shm_mq_inc_bytes_read ( mq , MAXALIGN (rb ) );
737
+ mqh -> mqh_consume_pending += MAXALIGN (rb );
737
738
738
739
/* If we got all the data, exit the loop. */
739
740
if (mqh -> mqh_partial_bytes >= nbytes )
740
741
break ;
741
742
742
743
/* Wait for some more data. */
743
744
still_needed = nbytes - mqh -> mqh_partial_bytes ;
744
- res = shm_mq_receive_bytes (mq , still_needed , nowait , & rb , & rawdata );
745
+ res = shm_mq_receive_bytes (mqh , still_needed , nowait , & rb , & rawdata );
745
746
if (res != SHM_MQ_SUCCESS )
746
747
return res ;
747
748
if (rb > still_needed )
@@ -1007,9 +1008,10 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
1007
1008
* is SHM_MQ_SUCCESS.
1008
1009
*/
1009
1010
static shm_mq_result
1010
- shm_mq_receive_bytes (shm_mq * mq , Size bytes_needed , bool nowait ,
1011
+ shm_mq_receive_bytes (shm_mq_handle * mqh , Size bytes_needed , bool nowait ,
1011
1012
Size * nbytesp , void * * datap )
1012
1013
{
1014
+ shm_mq * mq = mqh -> mqh_queue ;
1013
1015
Size ringsize = mq -> mq_ring_size ;
1014
1016
uint64 used ;
1015
1017
uint64 written ;
@@ -1021,7 +1023,13 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait,
1021
1023
1022
1024
/* Get bytes written, so we can compute what's available to read. */
1023
1025
written = pg_atomic_read_u64 (& mq -> mq_bytes_written );
1024
- read = pg_atomic_read_u64 (& mq -> mq_bytes_read );
1026
+
1027
+ /*
1028
+ * Get bytes read. Include bytes we could consume but have not yet
1029
+ * consumed.
1030
+ */
1031
+ read = pg_atomic_read_u64 (& mq -> mq_bytes_read ) +
1032
+ mqh -> mqh_consume_pending ;
1025
1033
used = written - read ;
1026
1034
Assert (used <= ringsize );
1027
1035
offset = read % (uint64 ) ringsize ;
@@ -1052,6 +1060,16 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait,
1052
1060
if (mq -> mq_detached )
1053
1061
return SHM_MQ_DETACHED ;
1054
1062
1063
+ /*
1064
+ * We didn't get enough data to satisfy the request, so mark any data
1065
+ * previously-consumed as read to make more buffer space.
1066
+ */
1067
+ if (mqh -> mqh_consume_pending > 0 )
1068
+ {
1069
+ shm_mq_inc_bytes_read (mq , mqh -> mqh_consume_pending );
1070
+ mqh -> mqh_consume_pending = 0 ;
1071
+ }
1072
+
1055
1073
/* Skip manipulation of our latch if nowait = true. */
1056
1074
if (nowait )
1057
1075
return SHM_MQ_WOULD_BLOCK ;
0 commit comments