Redis 6.0.7 fixes LPOS reply accounting
Redis 6.0.7 corrects malformed LPOS arrays when the requested rank exceeds available matches. It also fixes a loading-time client hang and allows TLS on internal links without a TLS client listener.
An empty search result must still produce a valid protocol reply. Redis 6.0.7 fixes an LPOS case where asking for a match beyond the available occurrences could produce a negative array length. The database did not need to crash for the client to encounter a failure. An invalid response framing was enough to break the command exchange.
The release notes date the patch to August 28, 2020. The versioned notes rate it moderate and specifically identify two fixes involving client protocol behaviour. One is LPOS reply construction. The other concerns a client hanging after a configuration request arrives during loading.
I have used Redis since its release, and its small request-response model is part of its appeal. A command's semantic result and the representation of that result are both part of the interface. A valid empty array matters just as much as a successful response containing positions.
Matches and emitted results are different counts
The 6.0.6 LPOS implementation keeps a count of matches encountered during traversal. Rank determines how many occurrences to skip before returning positions. When the caller requests an array with COUNT, the old code derives its final length by subtracting the requested rank from the match count and adding one.
That arithmetic works when the search reaches the requested occurrence and starts emitting results. It fails to represent the case where too few matches exist. With one match and rank three, the expression produces minus one. The caller asked for a collection of positions, and there are no qualifying positions to return.
The 6.0.7 implementation adds an explicit array-length variable initialised to zero. During traversal, the handler increments it only when it actually emits a position into the array. The deferred reply length then uses that variable.
This ties the framing to the output produced. Counting encountered matches still supports rank selection. Counting emitted positions supports the array length. The two counters represent different facts and no longer need the same arithmetic to stand in for both.
A missing occurrence is a normal query result
A simple example uses a disposable list containing one occurrence of the target. The search asks for the third occurrence and an array containing at most one qualifying position.
DEL lpos-framing-example
RPUSH lpos-framing-example a b c
LPOS lpos-framing-example c RANK 3 COUNT 1
In 6.0.7 the result is an empty array. The request is valid even though the requested occurrence is absent. The implementation does not reject rank three merely because this particular list has fewer matches.
That distinction is useful for applications searching mutable lists. The requested rank describes the desired occurrence. It is not a claim that the occurrence already exists, so the reply format needs to cover absence. A client should be able to handle that ordinary result without encountering malformed protocol.
The fix also explains why single-value and array replies need separate treatment. Without COUNT, the handler returns a position or a null result. With COUNT, it prepares an array header before traversal and fills in the length afterwards. The bug belongs to that deferred-length accounting path.
Loading rejection must leave the connection usable
The other highlighted fix involves CONFIG SET during RDB or append-only loading. The notes describe a hang when the request is processed after another command has already received a loading error. That sequence matters because the first rejected request affects how the subsequent request is handled.
The release description supports a precise claim about the fixed sequence. It does not establish that every loading request previously hung or that the configuration command should be allowed to modify the server during loading. The issue is keeping the client exchange well-formed when requests cannot proceed normally.
Together, these fixes show two ways a valid application can encounter an unusable connection. One response can have the wrong framing, or the server can fail to provide the expected progress after a rejection. Both require attention to the request sequence rather than only the dataset returned.
TLS can serve internal links separately
The patch also permits TLS for replication and cluster connections without requiring a TLS client-listening port. The release notes distinguish this from client-certificate verification changes. A deployment can have a transport policy for internal Redis links that differs from its client-facing listener configuration.
Other corrections include making PERSIST invalidate WATCH, matching the expiration-related transaction behaviour described in the notes. The patch also prevents an out-of-memory condition from rejecting a transaction composed only of reads. These are changes to which client operations receive meaningful results under particular conditions.
I value the LPOS correction because its implementation is small enough to make the reasoning explicit. The response length now counts positions actually written into the reply. A search that never reaches the requested rank retains a zero count, which represents the empty result without borrowing an arithmetic expression whose assumptions do not hold.