| 1496 | boundaries, just the entries. */ |
| 1497 | #define STREAM_RWR_HISTORY (1<<2) /* Only serve consumer local PEL. */ |
| 1498 | size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end, size_t count, int rev, streamCG *group, streamConsumer *consumer, int flags, streamPropInfo *spi) { |
| 1499 | void *arraylen_ptr = NULL; |
| 1500 | size_t arraylen = 0; |
| 1501 | streamIterator si; |
| 1502 | int64_t numfields; |
| 1503 | streamID id; |
| 1504 | int propagate_last_id = 0; |
| 1505 | int noack = flags & STREAM_RWR_NOACK; |
| 1506 | |
| 1507 | /* If the client is asking for some history, we serve it using a |
| 1508 | * different function, so that we return entries *solely* from its |
| 1509 | * own PEL. This ensures each consumer will always and only see |
| 1510 | * the history of messages delivered to it and not yet confirmed |
| 1511 | * as delivered. */ |
| 1512 | if (group && (flags & STREAM_RWR_HISTORY)) { |
| 1513 | return streamReplyWithRangeFromConsumerPEL(c,s,start,end,count, |
| 1514 | consumer); |
| 1515 | } |
| 1516 | |
| 1517 | if (!(flags & STREAM_RWR_RAWENTRIES)) |
| 1518 | arraylen_ptr = addReplyDeferredLen(c); |
| 1519 | streamIteratorStart(&si,s,start,end,rev); |
| 1520 | while(streamIteratorGetID(&si,&id,&numfields)) { |
| 1521 | /* Update the group last_id if needed. */ |
| 1522 | if (group && streamCompareID(&id,&group->last_id) > 0) { |
| 1523 | group->last_id = id; |
| 1524 | /* Group last ID should be propagated only if NOACK was |
| 1525 | * specified, otherwise the last id will be included |
| 1526 | * in the propagation of XCLAIM itself. */ |
| 1527 | if (noack) propagate_last_id = 1; |
| 1528 | } |
| 1529 | |
| 1530 | /* Emit a two elements array for each item. The first is |
| 1531 | * the ID, the second is an array of field-value pairs. */ |
| 1532 | addReplyArrayLen(c,2); |
| 1533 | addReplyStreamID(c,&id); |
| 1534 | |
| 1535 | addReplyArrayLen(c,numfields*2); |
| 1536 | |
| 1537 | /* Emit the field-value pairs. */ |
| 1538 | while(numfields--) { |
| 1539 | unsigned char *key, *value; |
| 1540 | int64_t key_len, value_len; |
| 1541 | streamIteratorGetField(&si,&key,&value,&key_len,&value_len); |
| 1542 | addReplyBulkCBuffer(c,key,key_len); |
| 1543 | addReplyBulkCBuffer(c,value,value_len); |
| 1544 | } |
| 1545 | |
| 1546 | /* If a group is passed, we need to create an entry in the |
| 1547 | * PEL (pending entries list) of this group *and* this consumer. |
| 1548 | * |
| 1549 | * Note that we cannot be sure about the fact the message is not |
| 1550 | * already owned by another consumer, because the admin is able |
| 1551 | * to change the consumer group last delivered ID using the |
| 1552 | * XGROUP SETID command. So if we find that there is already |
| 1553 | * a NACK for the entry, we need to associate it to the new |
| 1554 | * consumer. */ |
| 1555 | if (group && !noack) { |
no test coverage detected