valkey: la familia «caché en memoria» estaba VACÍA — y el artefacto salió vacío sin que nada fallara
`scripts/mudanza/planear.py` agrupa el software del origen en familias funcionales y contesta, para
cada una, con qué la reemplaza takana. Cruzando esa tabla contra el catálogo, cuatro familias salen
SIN NADA sellado: caché en memoria, contenedores, correo y base vectorial. Ésta cierra la primera.
Valkey y no redis a propósito: redis dejó de ser software libre en 2024 (RSALv2/SSPLv1, que no pasan
la OSI); valkey es el fork de la Linux Foundation desde el último commit BSD, mismo protocolo y mismo
RDB/AOF. Y upstream instala los seis alias `redis-*`, así que un `redis-server` se reemplaza sin
tocar datos ni clientes. Para una distro que publica el catálogo con `license` poblado receta a
receta, meter SSPL sería meter algo que después hay que sacar.
**El hallazgo caro de esta receta no fue compilar: fue que el PRIMER artefacto se selló VACÍO.**
`make install PREFIX=/usr DESTDIR=/out` imprimió sus `INSTALL valkey-server` en verde y salió 0 — y
`/out` quedó sin un solo fichero. La causa está en la línea 65 de `src/Makefile`: valkey define
`INSTALL_BIN=$(PREFIX)/bin` **sin prefijar `$(DESTDIR)`**, o sea que IGNORA `DESTDIR` y copió los
binarios a `/usr/bin` dentro del sandbox, que se tira al terminar. Lo sellado fue un directorio con
`.hammer/recipe.toml` y nada más: un cache-hit permanente que habría contestado «valkey ya está»
para siempre. Es la regla 3 del repo en vivo — *un ausente falla ruidosamente; un vacío llega hasta
el final diciendo que todo fue bien*. Se vio mirando el árbol del artefacto, NO el código de salida.
El arreglo es `PREFIX=/out/usr`.
El otro muro, medido con un control mínimo fuera de valkey: con `zig cc` el link muere con
`undefined symbol: __cpu_model` en los tres binarios. No es valkey — es que `__builtin_cpu_supports()`
(que valkey usa para elegir en runtime las rutas AVX2/AVX-512) emite esa referencia y el
`compiler_rt` de zig 0.16.0 no la trae:
printf '#include <stdio.h>\nint main(void){__builtin_cpu_init();return printf("%d",__builtin_cpu_supports("avx2"));}\n' > t.c
zig cc -target x86_64-linux-musl -O2 -o t t.c ⇒ ld.lld: error: undefined symbol: __cpu_model
De ahí `compiler = "gcc"`, que es la palanca declarativa que el lab expone justo para esto. Arrancarle
el multiversioning a parches habría costado las rutas SIMD de `BITCOUNT`/`PFCOUNT` y habría que
rehacer el parche en cada versión.
Verificado: REPRODUCE bit a bit. Único NEEDED `libc.so`, que provee `musl-shared` — raíz de `base`
desde hoy ⇒ resuelve en cualquier imagen sin declarar nada en la receta.
This commit is contained in:
+31
-10
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"schema": "hammer-build-state/1",
|
||||
"totals": {
|
||||
"recipes": 881,
|
||||
"nodes": 883,
|
||||
"sealed": 881,
|
||||
"recipes": 882,
|
||||
"nodes": 884,
|
||||
"sealed": 882,
|
||||
"ajeno": 2
|
||||
},
|
||||
"by_class": {
|
||||
"ajeno": 2,
|
||||
"c": 238,
|
||||
"c": 239,
|
||||
"go": 362,
|
||||
"gui": 41,
|
||||
"kernel": 6,
|
||||
@@ -17,7 +17,7 @@
|
||||
"debt_by_class": {},
|
||||
"by_queue": {
|
||||
"corpus": {
|
||||
"sealed": 881,
|
||||
"sealed": 882,
|
||||
"ajeno": 2
|
||||
}
|
||||
},
|
||||
@@ -43,7 +43,7 @@
|
||||
"sealed": 101
|
||||
}
|
||||
},
|
||||
"sin_perfil": 643,
|
||||
"sin_perfil": 644,
|
||||
"orphan_deps": [],
|
||||
"topo_ok": true,
|
||||
"nodes": {
|
||||
@@ -1005,7 +1005,7 @@
|
||||
"escritorio-sway",
|
||||
"servidor"
|
||||
],
|
||||
"dependientes_total": 52
|
||||
"dependientes_total": 53
|
||||
},
|
||||
"biome": {
|
||||
"iname": "biome",
|
||||
@@ -1282,7 +1282,7 @@
|
||||
"escritorio-sway",
|
||||
"servidor"
|
||||
],
|
||||
"dependientes_total": 12
|
||||
"dependientes_total": 13
|
||||
},
|
||||
"bwrap": {
|
||||
"iname": "bwrap",
|
||||
@@ -10786,7 +10786,7 @@
|
||||
"escritorio-sway",
|
||||
"servidor"
|
||||
],
|
||||
"dependientes_total": 128
|
||||
"dependientes_total": 129
|
||||
},
|
||||
"mako": {
|
||||
"iname": "mako",
|
||||
@@ -13150,7 +13150,7 @@
|
||||
"escritorio-sway",
|
||||
"servidor"
|
||||
],
|
||||
"dependientes_total": 410
|
||||
"dependientes_total": 411
|
||||
},
|
||||
"plow": {
|
||||
"iname": "plow",
|
||||
@@ -16538,6 +16538,27 @@
|
||||
"perfiles": [],
|
||||
"dependientes_total": 0
|
||||
},
|
||||
"valkey": {
|
||||
"iname": "valkey",
|
||||
"version": "9.1.2",
|
||||
"link": "dynamic",
|
||||
"compiler": "gcc",
|
||||
"deps": [
|
||||
"binutils",
|
||||
"busybox",
|
||||
"make",
|
||||
"pkgconf"
|
||||
],
|
||||
"cls": "c",
|
||||
"queue": "corpus",
|
||||
"foreign": false,
|
||||
"hash": "b3:9571c1a691ff8dd2e91611a341d2ddab11a9cc9a030ed8054006a4626542a06f",
|
||||
"state": "sealed",
|
||||
"blocked_by": [],
|
||||
"unblocks": 0,
|
||||
"perfiles": [],
|
||||
"dependientes_total": 0
|
||||
},
|
||||
"vals": {
|
||||
"iname": "vals",
|
||||
"version": "0.44.1",
|
||||
|
||||
@@ -75,3 +75,4 @@ popt 7202a918f06efe0315267027b071f5380f77aa15ce59eac83b5f078e6edd24f4 2026-09-11
|
||||
logrotate 09698cb83519dc2423b8aa1905fa5803955ee1c79598590c30ff5b5b14e5e84d 2026-09-11 reproduce
|
||||
chrony b9e26374f000ef5820bcc32bdb761b2b3e7306d1ed400c147271cfdbd77557e9 2026-09-11 reproduce
|
||||
cronie 387347b89b107d97febbb2692ce2d292e74bc7b1fba105676befe396cc3ebf21 2026-09-11 reproduce
|
||||
valkey 9571c1a691ff8dd2e91611a341d2ddab11a9cc9a030ed8054006a4626542a06f 2026-09-11 reproduce
|
||||
|
||||
|
@@ -0,0 +1,91 @@
|
||||
# valkey 9.1.2 — la caché en memoria. Entra por un hueco que se ve desde la herramienta de mudanza:
|
||||
# `scripts/mudanza/planear.py` agrupa el software del origen en FAMILIAS funcionales y contesta, para
|
||||
# cada una, si takana tiene con qué reemplazarla. Cruzada contra el catálogo, la familia «caché en
|
||||
# memoria» salía SIN NADA: ni redis, ni valkey, ni memcached — o sea que si el servidor de origen usa
|
||||
# una, la migración se para en seco y se entera tarde.
|
||||
#
|
||||
# **Por qué valkey y no redis, que es el que todo el mundo tiene corriendo.** No es gusto: redis dejó
|
||||
# de ser software libre en 2024 (RSALv2/SSPLv1, licencias que no pasan la OSI) y valkey es el fork que
|
||||
# la Linux Foundation sacó del último commit BSD, manteniendo el protocolo y el formato de RDB/AOF. Un
|
||||
# `redis-server` se reemplaza por `valkey-server` sin tocar los datos ni los clientes. Para una distro
|
||||
# que publica su catálogo con el campo `license` poblado receta a receta, meter SSPL sería meter algo
|
||||
# que después hay que sacar.
|
||||
#
|
||||
# `MALLOC=libc` — valkey trae jemalloc vendorizado y lo usa por default en Linux. No acá: jemalloc
|
||||
# asume glibc en varios sitios y el corpus es musl. `libc` es lo que usa Alpine para lo mismo. Ojo
|
||||
# con el costo real, que no es cero: jemalloc es lo que le da a valkey la defragmentación activa
|
||||
# (`activedefrag`), así que con `MALLOC=libc` esa opción no existe. Es la decisión correcta igual —
|
||||
# un valkey que arranca sin defrag le gana a uno que no compila— pero queda dicho y no escondido.
|
||||
#
|
||||
# **Lo que NO hizo falta parchear, y vale la pena por qué:** `src/debug.c` usa `backtrace()` de
|
||||
# `execinfo.h`, que musl no tiene. Upstream ya lo resuelve bien en `src/config.h`: pide
|
||||
# `__linux__ && __GLIBC__` para definir `HAVE_BACKTRACE`, y musl no define `__GLIBC__`. Sale sin el
|
||||
# volcado de pila en los crashes, que es la misma renuncia que hace Alpine.
|
||||
#
|
||||
# ⚠ **`compiler = "gcc"`, Y ESTO ESTÁ MEDIDO CON UN CONTROL MÍNIMO, NO SUPUESTO.** Con el `zig cc`
|
||||
# por defecto el link muere en los tres binarios con `ld.lld: error: undefined symbol: __cpu_model`.
|
||||
# La causa no es valkey: `src/util.c`, `src/bitops.c` y `src/hyperloglog.c` usan
|
||||
# `__builtin_cpu_supports()` para elegir en runtime las rutas AVX2/AVX-512, y ese builtin emite una
|
||||
# referencia a `__cpu_model`, que provee la runtime del compilador (libgcc). El `compiler_rt` de
|
||||
# zig 0.16.0 NO la trae. Comprobado fuera de valkey, con seis líneas:
|
||||
#
|
||||
# printf '#include <stdio.h>\nint main(void){__builtin_cpu_init();return printf("%%d",__builtin_cpu_supports("avx2"));}\n' > t.c
|
||||
# zig cc -target x86_64-linux-musl -O2 -o t t.c ⇒ ld.lld: error: undefined symbol: __cpu_model
|
||||
#
|
||||
# Por eso el escape es declarativo y no un parche: `compiler = "gcc"` es exactamente la palanca que
|
||||
# el lab expone para «lld estricto de zig no linkea esto», y libgcc sí define `__cpu_model`.
|
||||
# Arrancarle el multiversioning a valkey a parches habría sido peor: se pierden las rutas SIMD que
|
||||
# son la mitad del rendimiento de `BITCOUNT` y `PFCOUNT`, y el parche hay que rehacerlo en cada
|
||||
# versión.
|
||||
#
|
||||
# `OPTIMIZATION=-O2` apaga el LTO que valkey enciende sola cuando la optimización es `-O3` (su
|
||||
# `src/Makefile` añade `-flto=auto -ffat-lto-objects`). No es por el `__cpu_model` —eso falla con y
|
||||
# sin LTO, se probó— sino porque un LTO de fábrica sobre un árbol con seis deps vendorizadas es
|
||||
# superficie de fallo que esta receta no necesita para su primera versión sellada.
|
||||
#
|
||||
# La reproducibilidad la trae upstream y conviene decir dónde: `src/mkreleasehdr.sh` hornea un
|
||||
# `REDIS_BUILD_ID` que por default es `uname -n` + `date +%s` —la familia exacta del sello de tiempo
|
||||
# de nftables— pero el script mira `SOURCE_DATE_EPOCH`, que el lab exporta.
|
||||
#
|
||||
# Lo que sale, comprobado sobre el artefacto sellado y no sobre el código de salida: `valkey-server`
|
||||
# (10,4 M), `valkey-cli`, `valkey-benchmark`, los symlinks de sentinel/check-rdb/check-aof y —esto
|
||||
# importa para migrar— los seis alias `redis-*`, que upstream instala solo. `valkey-server --version`
|
||||
# contesta `v=9.1.2 malloc=libc`. Su único NEEDED es `libc.so`, que lo provee `musl-shared`, raíz del
|
||||
# perfil `base` ⇒ resuelve en cualquier imagen sin declarar nada acá.
|
||||
#
|
||||
# `link = "dynamic"`: valkey enlaza C y C++ (la dep `fast_float` es C++), y la runtime de C++ del
|
||||
# corpus se publica compartida. Un `link = "static"` acá sellaría un binario dinámico igual y la
|
||||
# receta estaría mintiendo — la familia de fallos del `link=static` por libtool, vista de otro lado.
|
||||
name = "valkey"
|
||||
version = "9.1.2"
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
[source]
|
||||
tarball = "https://github.com/valkey-io/valkey/archive/refs/tags/9.1.2.tar.gz"
|
||||
sha256 = "19c23908e7d57e8d91ef85b41f5646307582f10f4f0fb999bbf89ed24ec9c983"
|
||||
|
||||
[build]
|
||||
compiler = "gcc"
|
||||
target = "x86_64-linux-musl"
|
||||
link = "dynamic"
|
||||
flags = []
|
||||
|
||||
[build.phases]
|
||||
# `configure = 'true'` NO ES RELLENO. valkey 9 trae `CMakeLists.txt` ADEMÁS del `Makefile` clásico,
|
||||
# y la heurística del lab detecta CMake primero ⇒ inyecta un `cmake -S . -B _build …` que muere con
|
||||
# `cmake: not found` (el corpus no tiene cmake en las deps de esta receta). El no-op apaga esa fase
|
||||
# y deja el camino que upstream mantiene como principal, que es `make` sobre `src/Makefile`.
|
||||
configure = 'true'
|
||||
compile = 'make -j"$(nproc)" MALLOC=libc PREFIX=/usr OPTIMIZATION=-O2'
|
||||
# ⚠ **`PREFIX=/out/usr` Y NO `DESTDIR=/out`, Y ESTO CASI PASA INADVERTIDO.** El `src/Makefile` de
|
||||
# valkey **IGNORA `DESTDIR`**: define `INSTALL_BIN=$(PREFIX)/bin` a secas (línea 65), sin prefijar
|
||||
# `$(DESTDIR)`. Con `PREFIX=/usr DESTDIR=/out` el `make install` imprime sus `INSTALL valkey-server`
|
||||
# en verde, sale 0, y copia los binarios a `/usr/bin` DENTRO del sandbox — un overlay que se tira al
|
||||
# terminar. El resultado fue un artefacto SELLADO con `.hammer/recipe.toml` y NADA MÁS: la regla 3
|
||||
# del repo en vivo («un ausente falla ruidosamente; un vacío llega hasta el final diciendo que todo
|
||||
# fue bien»), y peor, un cache-hit permanente que habría contestado «valkey ya está» para siempre.
|
||||
# Se detectó mirando el árbol del artefacto, no el código de salida.
|
||||
install = 'make install MALLOC=libc PREFIX=/out/usr'
|
||||
|
||||
[deps]
|
||||
build = ["binutils", "busybox", "make", "pkgconf"]
|
||||
Reference in New Issue
Block a user