Redis 3.2.8 rolls back jemalloc and fixes migration cleanup
Redis 3.2.8 reverses the bundled jemalloc upgrade after suspected deadlocks. Its MIGRATE fix also shows how rewriting a command can invalidate arguments needed by an error path.
Redis 3.2.8 reverses an allocator upgrade made less than two weeks earlier. The maintainers believe jemalloc 4.4.0 may deadlock under particular conditions, so the release restores the previous bundled version while investigation continues. The decision separates restoring a known dependency from establishing the complete cause of the reported failure.
The 3.2 release notes date 3.2.8 to 12 February and classify its urgency as critical. The versioned release notes also identify a MIGRATE crash after a socket error. That second fix has a precise explanation in the patch, involving cleanup code that reads command arguments after another part of the operation has replaced them.
I like Redis's compact operational model, but its allocator is still a consequential dependency. A server can stop making progress below the level of its command implementation. The release's wording is appropriately limited to a suspected deadlock while making the rollback decision explicit.
The bundled dependency changes back
Redis 3.2.7 had upgraded jemalloc to 4.4.0. Its notes described possible improvements in memory use and reclamation compared with the early 4.0 version previously bundled. Redis 3.2.8 reverts that upgrade rather than adding a speculative allocator patch of its own.
The VERSION file in 3.2.8 identifies the restored dependency as 4.0.3 with its source revision. That gives the rollback a concrete meaning. The release returns to the earlier bundled code while preserving the other changes on the Redis maintenance line.
The release notes say the project plans to upgrade jemalloc again after obtaining more information about the cause. They do not establish that every hang in every build comes from this allocator version. Maintaining that uncertainty matters because a mitigation can be justified before the investigation has answered every causal question.
A dependency rollback also has a narrower scope than reversing the entire Redis release. The earlier maintenance update contained protocol protection and data-correctness work as well as the allocator change. The new release specifically reverts the allocator commit and adds the migration correction, so users do not have to abandon the other maintenance fixes to receive the rollback.
MIGRATE rewrites the command for propagation
The migration fix explains why error cleanup could crash the server. MIGRATE can replace its original client argument vector with a DEL operation for replication and the append-only file. After that replacement, the original host and port arguments no longer occupy their former positions.
That rewrite has a defined purpose. For a non-copying migration, keys acknowledged by the receiving server are removed from the source. The patch comment says that the propagated DEL includes only keys for which the source received acknowledgment. This records the source-side deletion in a form suitable for replication and persistence.
The error path nevertheless needed the original destination to close a cached migration socket. It called migrateCloseSocket using positions in the client's argument vector. If the vector had already become a DEL, those positions could contain unrelated values or a null pointer. The commit message identifies dereferencing that pointer as a cause of the server crash.
This is a lifetime problem in shared operation state. One part of the function still treats the arguments as a migration request, while another part has transformed them into a record of the deletions to propagate. Both interpretations are locally reasonable, but they cannot remain valid over the same vector after the rewrite.
Cleanup moves before the destructive rewrite
The patch closes the cached socket earlier when a later-stage socket error occurs and no retry will happen. At that point, the original host and port are still available. Only afterward does the function replace the command vector with DEL where acknowledged keys require it.
An argv_rewritten flag records whether that replacement happened. The later socket_err cleanup path checks the flag before trying to close the socket again. The source comment notes that closing the socket is itself idempotent, but the arguments needed to identify it have disappeared. Repeating an otherwise safe cleanup function is unsafe when its input no longer has the expected meaning.
This distinction is the mechanism behind the correction. Making migrateCloseSocket tolerate repeated calls would not restore the lost host and port. The fix orders cleanup while those arguments are valid and prevents the later path from treating rewritten data as the original request.
I find this patch useful as an explanation of why an uncommon error can have a severe consequence. A normal migration can exercise the command rewrite successfully. The crash requires the cleanup path to run under the particular socket-error conditions that expose the stale interpretation of the argument vector.
Failure handling preserves the acknowledged subset
The patch also keeps the distinction between keys acknowledged by the destination and keys not acknowledged. It builds the propagated deletion using the acknowledged subset, and the comments make that condition explicit. A migration that encounters a socket error can therefore have more state to describe than a simple all-or-nothing success flag.
Once the function reaches the described later stage with a socket error, it disables retry and reports the problem unless the destination has already supplied another error. Earlier retry handling remains separate. The change does not describe retrying every failed migration or treating every socket error as harmless.
Closing the cached socket also forces a database selection on the next connection, according to the cleanup comment. Socket reuse therefore carries connection state as well as a destination address, which explains why the function maintains a cache entry.
These details explain why the release includes the migration crash alongside the allocator rollback. One correction restores a dependency while its suspected deadlock remains under investigation. The other changes the order and conditions of cleanup around a command-vector rewrite. In both cases the maintenance release identifies a specific route to losing server progress, with the migration patch preserving the destination acknowledgments needed for source-side deletion.