3737
3838void streamFreeCGGeneric (void * cg , void * s );
3939void streamFreeNACK (stream * s , streamNACK * na );
40- size_t streamReplyWithRangeFromConsumerPEL (client * c , stream * s , streamID * start , streamID * end , size_t count , streamCG * group , streamConsumer * consumer , long long maxsize , size_t emitted_before , size_t maxsize_base );
40+ size_t streamReplyWithRangeFromConsumerPEL (client * c , stream * s , streamID * start , streamID * end , size_t count , streamCG * group , streamConsumer * consumer , long long maxsize , size_t emitted_before );
4141int streamParseStrictIDOrReply (client * c , robj * o , streamID * id , uint64_t missing_seq , int * seq_given );
4242int streamParseIDOrReply (client * c , robj * o , streamID * id , uint64_t missing_seq );
4343
@@ -1967,12 +1967,12 @@ void streamPropagateConsumerCreation(client *c, robj *key, robj *groupname, sds
19671967/* Returns non-zero if the MAXSIZE byte budget has been reached. 'maxsize' is the
19681968 * budget (0 = no limit) and 'emitted' the entries emitted so far; the budget is
19691969 * only enforced after at least one entry, so a single oversized message can still
1970- * exceed it. The budget applies to the delta from 'maxsize_base' (output bytes at
1971- * serve-start) so earlier commands in the same MULTI/EXEC don't count; outside a
1972- * transaction the base is 0. */
1973- static inline int streamReplyMaxsizeReached (client * c , long long maxsize , size_t emitted , size_t maxsize_base ) {
1970+ * exceed it. 'maxsize' already includes the output-bytes baseline (output bytes at
1971+ * serve-start), so earlier commands in the same MULTI/EXEC don't count; outside a
1972+ * transaction the baseline is 0. */
1973+ static inline int streamReplyMaxsizeReached (client * c , long long maxsize , size_t emitted ) {
19741974 return maxsize && emitted > 0 &&
1975- ( c -> net_output_bytes_curr_cmd - maxsize_base ) >= (size_t )maxsize ;
1975+ c -> net_output_bytes_curr_cmd >= (size_t )maxsize ;
19761976}
19771977
19781978/* Send the stream items in the specified range to the client 'c'. The range
@@ -2059,7 +2059,6 @@ size_t streamReplyWithRange(client *c, stream *s, streamReplyRangeArgs *args) {
20592059 unsigned long * propCount = args -> propCount ;
20602060 long long maxsize = args -> maxsize ;
20612061 size_t emitted_before = args -> emitted_before ;
2062- size_t maxsize_base = args -> maxsize_base ;
20632062 void * arraylen_ptr = NULL ;
20642063 size_t arraylen = 0 ;
20652064 streamIterator si ;
@@ -2105,7 +2104,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamReplyRangeArgs *args) {
21052104 uint64_t idle = cmd_time_snapshot - nack -> delivery_time ;
21062105 if (idle < (uint64_t )min_idle_time ) break ;
21072106
2108- if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen , maxsize_base ))
2107+ if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen ))
21092108 break ;
21102109
21112110 /* Process and claim this entry */
@@ -2180,7 +2179,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamReplyRangeArgs *args) {
21802179 }
21812180 return streamReplyWithRangeFromConsumerPEL (c ,s ,start ,end ,count ,
21822181 group , consumer ,
2183- maxsize , emitted_before , maxsize_base );
2182+ maxsize , emitted_before );
21842183 }
21852184
21862185 /* Stop here if client only wants claimed entries or count is satisfied. */
@@ -2200,7 +2199,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamReplyRangeArgs *args) {
22002199 while (streamIteratorGetID (& si ,& id ,& numfields )) {
22012200 /* Break before delivering the entry so it is neither sent nor added to
22022201 * the consumer's PEL. */
2203- if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen , maxsize_base ))
2202+ if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen ))
22042203 break ;
22052204
22062205 /* Update the group last_id if needed. */
@@ -2343,7 +2342,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamReplyRangeArgs *args) {
23432342 * seek into the radix tree of the messages in order to emit the full message
23442343 * to the client. However clients only reach this code path when they are
23452344 * fetching the history of already retrieved messages, which is rare. */
2346- size_t streamReplyWithRangeFromConsumerPEL (client * c , stream * s , streamID * start , streamID * end , size_t count , streamCG * group , streamConsumer * consumer , long long maxsize , size_t emitted_before , size_t maxsize_base ) {
2345+ size_t streamReplyWithRangeFromConsumerPEL (client * c , stream * s , streamID * start , streamID * end , size_t count , streamCG * group , streamConsumer * consumer , long long maxsize , size_t emitted_before ) {
23472346 raxIterator ri ;
23482347 unsigned char startkey [sizeof (streamID )];
23492348 unsigned char endkey [sizeof (streamID )];
@@ -2356,7 +2355,7 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
23562355 raxSeek (& ri ,">=" ,startkey ,sizeof (startkey ));
23572356 while (raxNext (& ri ) && (!count || arraylen < count )) {
23582357 if (end && memcmp (ri .key ,endkey ,ri .key_len ) > 0 ) break ;
2359- if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen , maxsize_base ))
2358+ if (streamReplyMaxsizeReached (c , maxsize , emitted_before + arraylen ))
23602359 break ;
23612360 streamID thisid ;
23622361 streamDecodeID (ri .key ,& thisid );
@@ -2983,15 +2982,17 @@ void xreadCommand(client *c) {
29832982 mstime_t min_pel_delivery_time = LLONG_MAX ;
29842983 size_t total_entries = 0 ; /* Entries emitted so far across all streams,
29852984 used to enforce MAXCOUNT/MAXSIZE. */
2986- /* MAXSIZE budget baseline: bytes accumulated before serving (non-zero inside
2987- * MULTI/EXEC). The budget is enforced on the delta from this value. */
2988- size_t maxsize_base = c -> net_output_bytes_curr_cmd ;
2985+ /* MAXSIZE budget baseline: fold the bytes accumulated before serving
2986+ * (non-zero inside MULTI/EXEC) into the budget so MAXSIZE is enforced on the
2987+ * absolute c->net_output_bytes_curr_cmd. Only adjust a real (non-zero) budget,
2988+ * since maxsize == 0 means "no limit". */
2989+ if (maxsize ) maxsize += c -> net_output_bytes_curr_cmd ;
29892990 for (int i = 0 ; i < streams_count ; i ++ ) {
29902991 /* Stop scanning further streams once a cumulative limit is reached.
29912992 * At least the first stream is always served, so a single message
29922993 * larger than MAXSIZE is still returned. */
29932994 if (maxcount && total_entries >= (size_t )maxcount ) break ;
2994- if (streamReplyMaxsizeReached (c , maxsize , total_entries , maxsize_base )) break ;
2995+ if (streamReplyMaxsizeReached (c , maxsize , total_entries )) break ;
29952996
29962997 kvobj * o = lookupKeyRead (c -> db , c -> argv [streams_arg + i ]);
29972998 if (o == NULL ) continue ;
@@ -3123,7 +3124,6 @@ void xreadCommand(client *c) {
31233124 .group = groups ? groups [i ] : NULL , .consumer = consumer ,
31243125 .flags = flags , .spi = & spi , .propCount = & propCount ,
31253126 .maxsize = maxsize , .emitted_before = total_entries ,
3126- .maxsize_base = maxsize_base ,
31273127 };
31283128 total_entries += streamReplyWithRange (c ,s ,& args );
31293129 if (server .memory_tracking_enabled )
0 commit comments