# 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 \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"]