[BUG] ARLASTITEMS silently drops an existing element when the walked range has a hole
Describe the bug
When there is a hole among the positions ARLASTITEMS walks, and count is greater than the number of existing elements, the reply stops early and silently leaves out existing elements.
To reproduce
On unstable at 20bb2cfc5:
> ARINSERT log a b c d e
(integer) 4
> ARDEL log 1
(integer) 1
> ARGETRANGE log 0 4
1) "a"
2) (nil)
3) "c"
4) "d"
5) "e"
> ARLASTITEMS log 10
1) (nil)
2) "c"
3) "d"
4) "e"a is still in the array, but it is not in the reply, and nothing tells the caller that the reply is incomplete.
Expected behavior
ARLASTITEMS walks positions and returns NULL for holes, as the comment above arlastitemsCommand says. With 5 positions and count 10, all positions should be returned:
1) "a"
2) (nil)
3) "c"
4) "d"
5) "e"Additional information
The number of steps is capped by the number of existing elements, not by the number of positions (src/t_array.c:1837):
uint64_t effective_count =
(uint64_t)count > ar->count ? ar->count : (uint64_t)count;Each hole uses up one of those steps, so the walk ends before it reaches the oldest elements.
The fix caps the walk by arLen(ar) instead. On a sparse array this lets the reply grow to the array length, so it also adds a hard limit like the ARGETRANGE one (the comment at src/t_array.c:442): when min(count, arLen(ar)) exceeds both 1 million and the number of existing elements, ARLASTITEMS replies with an error instead of trimming. Replies that fit in the existing elements are not limited, so dense arrays behave as today.
Source: redis/redis