Drizzle Revival (2026)¶
- Status:
In progress
- Target endpoint:
Ubuntu 26.04 LTS, multi-arch (amd64 + arm64) container
- Last updated:
2026-05
Status and next¶
A fast orientation for any agent or contributor opening this file cold. Read this block first; the rest of the spec is the roadmap.
Landed. Phase 0 (tests in container, Zuul scaffolding sitting inert under
future-zuul.d/, this spec landed), Phase 1 (dead-platform strip,m4/pandora_*.m4simplifications, dead-dep plugins deleted), Phase 2 (performance baseline harness underperf/), Phase 3 (container hygiene and Phase 0 follow-ups), Phase 4 (LTS bump 12.04 → 14.04), Phase 5 (LTS bump 14.04 → 16.04; C++11 baseline;boost::shared_ptr/boost::unordered_mapswept tostd::), Phase 6 (LTS bump 16.04 → 18.04; Boost 1.65 link-graph fix-ups; GCC 7-Wimplicit-fallthrough/-Wmemset-elt-size/-Wbool-compare/-Wmisleading- indentationsweep;readdir_r→readdirand__sync_fetch_and_add→__atomic_load_n; C++03 dynamic- exception-spec sweep;drizzle_result_stconstructor was missing two pointer initialisers — Bionic’s stricter heap layout exposed the bug as afree(): invalid pointerin DTR’s auth path), Phase 7 (LTS bump 18.04 → 20.04; C++17 build mode, protobuf 3, PCRE2, Boost 1.71, Focal perf numbers, native-AIO perf comparison, and the C++17 mechanical source sweep), Phase 8 (LTS bump 20.04 → 22.04; Boost 1.74; OpenSSL 3 EVP migration for the SHA1/MD5/HMAC consumers; protobuf 3 modernByteSize()/ cached-size APIs; GCC 11 sweep including the Bison-generated parser’sYYNOMEMoverflow fall-through; the stack is split into a Focal-safe prep layer and the Jammy bump itself so every commit stays green on its base; Jammy perf numbers under valgrind 3.18 show stable IR against the Focal AIO run, with a toolchain-driven jump in simulated cache misses andestimated_cycles), and Phase 9 (LTS bump 22.04 → 24.04; Boost 1.83; GCC 13 / libstdc++ 13 sweep — dropped the deprecatedstd::unary_function/std::binary_function/std::iteratorbase classes that go away in C++20, movedboost::filesystem::change_extensiontopath::replace_extension, and cleaned up a latent infinite-recursion inmi_report_errorthat GCC finally noticed; ported the autoreconf-time pandora-plugin generator and themysql_protocol.prototestDTR suite from python2 to python3 because Noble drops python2 entirely; native AIO disabled because podman’s default seccomp profile rejects Noble’sio_pgeteventssyscall and the Phase 7 numbers showed native AIO was a wash anyway; Noble perf numbers stable against Jammy). Each landed phase’s commits are tagged in commit messages, under their old numbers for Phases 0–2 — what this spec now calls Phase 2 appears in older commits as Phase 1.5. See the Renumber note below for the full map.In flight, then paused. Phase 11 (Pandora slim-down to
m4/drizzle.m4) — what older commit messages call Phase 2. A number of build-setup macros have folded intom4/drizzle.m4(version, C++ standard, dtrace, platform, optimize, warnings, VC info); the headline work (library-presence macros toPKG_CHECK_MODULES, killing the lastAX_PTHREADcaller, finishing the bzr/svn/hg strip, thePANDORA_→DRIZZLE_rename) is open but deliberately deferred until after the LTS ratchet reaches 26.04.Next. Phase 10 (LTS bump 24.04 → 26.04, final landing). On the 26.04 toolchain we should also be able to jump straight to C++23 — GCC 14’s C++23 support is far enough along that doing the C++20 hop on 24.04’s GCC 13 first is wasted motion. The Pandora slim-down (Phase 11) is still held back because the existing Pandora layer still works, and the LTS ratchet brings in modern pkg-config / Boost / OpenSSL / protobuf that make the macro conversion cleaner than fighting the 12.04 toolchain. After the ratchet reaches 26.04: Phase 11 (Pandora slim-down), Phase 12 (constant-fold), Phase 13 (plugin enable-by-default sweep), Phase 14 (Sphinx-only docs).
Carry-overs from Phase 6. Two pre-existing items surfaced by the Bionic verification but deliberately left for follow-up: the
libdrizzle-1.0/t/race over hard-coded port 12399 is currently papered over withAUTOMAKE_OPTIONS = serial-tests; the longer question is whetherlibdrizzle-1.0should stay at all (drizzled andclient/link againstlibdrizzle-2.0; onlyunittests/libdrizzle_test.ccstill pulls in 1.0). Andarm64verification was skipped on this laptop session — Zuul’s arm64 nodes will pick up the gate.
Renumber note. This revision renumbered phases for linear sequencing. Map: 1.5 → 2, 1.6 → 3, old 3–9 → 4–10, old 2 → 11, old 2.5 → 12, old 10 → 13, old 11 → 14. Commits landed under the old numbers keep their commit messages; future commits use the new numbers.
This spec is the load-bearing roadmap for reviving the Drizzle code base from its 2013 state (Ubuntu 12.04 base, autotools + Pandora macro layer, no working tests in CI) to a modern, single-target, container-first database server.
A team of contributors (or subagents) executes this spec phase by phase.
Each phase has explicit Objective / Tasks / Done-when / Risks sections.
File paths and podman invocations are concrete; copy-paste is
expected.
Context and goals¶
Drizzle was last actively developed around 2013. The current state:
configure.acis at version 7.2; ~300 lines, plus a heavy “Pandora” m4 macro layer (~55 of 136 m4 files).The in-tree plugins are registered via
config/pandora-plugin.iniand aconfig/pandora-pluginPython enumeration script.The repo’s
Containerfilebuilds against Ubuntu 12.04 (Precise, long EOL) usingbindep-rsto installbindep.txt. The build runs; tests do not.Sphinx docs are well established (65 RST files); a
Doxyfilealso exists but Sphinx is the primary documentation surface.
We are reviving the project with a small set of strong constraints:
Single OS target, ever. Whatever the
ContainerfileFROMline says is the only environment we support. No portability code paths.Two CPU architectures:
linux/amd64andlinux/arm64. Both are 64-bit little-endian. Eventually shipped as a multi-arch podman manifest.Keep autotools.
automakemakefiles are loved;make distcheckmust keep working even if we never ship a source tarball.podman everywhere. Every documented build/test invocation uses
podman.Goal endpoint: Ubuntu 26.04 base, every plugin built by default, Sphinx-only docs, full Zuul CI on OpenDev.
Foundational principles¶
These principles apply throughout every phase. They are not optional.
Strip the check, hardcode the answer¶
When an autoconf probe is excised, the flag, define, or behavior it would have enabled on the target must remain. Examples:
AX_PTHREAD— don’t probe; unconditionally add-pthreadtoAM_CFLAGS/AM_CXXFLAGS/AM_LDFLAGSandAC_DEFINE([HAVE_PTHREAD],[1]).64-bit sizes — don’t probe
sizeof(void*); hardcodeSIZEOF_VOIDP=8,SIZEOF_LONG=8,SIZEOF_SIZE_T=8,SIZEOF_OFF_T=8,SIZEOF_LONG_LONG=8.Large-file support — don’t probe. On LP64 Linux
off_tis already 8 bytes by default, so-D_FILE_OFFSET_BITS=64is a no-op;config/top.h#undefs any caller-supplied value as deliberate neutralization (an outer build that sets_FILE_OFFSET_BITS=64is fine; one that sets it to32won’t silently downgrade us).POSIX/glibc-guaranteed functions (
memmove,strerror,inet_ntoa, etc.) — delete theAC_CHECK_FUNCSprobe; either delete the corresponding#ifdef HAVE_*in source orAC_DEFINEthe symbol unconditionally.Standard C++ headers (
<cstdint>,<unordered_map>,<memory>) — assume present.Visibility — don’t probe
gl_VISIBILITY; hardcodeCFLAG_VISIBILITY="-fvisibility=hidden"and apply it per-target on the libdrizzle libraries. A build-wide-fvisibility=hidden -fvisibility-inlines-hiddenpass needs every genuinely-public symbol annotated first and is tracked in Future work.Stack-direction probe (
DRIZZLE_STACK_DIRECTION) — hardcode “grows down”.Endianness — hardcode little-endian.
The end-state configure.ac does almost no probing but produces
the same config.h and same compile/link flags as the old one
would have on amd64/arm64 Linux.
For each deletion the contributor must verify that the corresponding
define/flag is preserved (via AC_DEFINE of a constant, via
unconditional AM_CPPFLAGS additions, or via deletion of the
now-redundant #ifdef in source).
Aggressive commit splitting; every commit green¶
Deep stacks of small commits are loved. Every bullet point in the phase task lists below is, by default, its own commit — often more than one. Removing the haildb plugin is one commit. Removing tokyocabinet is a second commit. Each independent
m4/pandora_*.m4deletion is its own commit.One semantic change per commit. A commit may contain only the deletion of dead code, or only the addition of a hardcoded equivalent. When deletion plus replacement together tell a single reviewable story, they go in one commit; when they tell two stories, two commits.
Every commit is fully green.
podman build --target=buildsucceeds,podman build --target=testsucceeds,make unitexits 0,make test-drizzleexits 0. No commit may break tests — not even transiently. If a change requires a sequence, structure the sequence so intermediate steps stay green (typical pattern: add new code → migrate callers → delete old code, three commits, each green).This invariant is bisect-load-bearing. Future debugging walks dozens of small commits with
git bisect; any “broken in the middle” commit defeats bisect for the rest of the stack.Zuul’s
vouchedandgatepipelines run on every commit in a stack, not just the tip. A red commit anywhere in the stack blocks the merge.Commit messages describe why, not what. The diff shows what.
No gravestone comments¶
When code is removed, it is gone. Git log is the breadcrumb. Do not
leave // removed X, /* was: ... */, or # this used to ...
comments in source files, m4 files, Makefile.am, plugin.ini,
or anywhere else.
The narrow exception: if a removal genuinely needs to warn future contributors away from re-introducing a pattern, a comment about the constraint is fine, but never about the history.
Current in-tree violations to clean up (cleanup itself lives under Phase 3):
configure.ac:47-49— describes whatgl_VISIBILITYused to do.m4/drizzle.m4:35-39— explains whatDRIZZLE_BUILD_SETUPreplaces.m4/drizzle.m4:369-371— narrates the prior probe-gated warning flags.
Multi-arch readiness from the start¶
Both targets (amd64 and arm64) are 64-bit, little-endian, 8-byte pointer. These are safe hardcoded assumptions. But:
No x86-only intrinsics (SSE/AVX) without an aarch64 fallback.
No x86-only inline asm.
Pandora’s host-architecture detection branches that distinguish
x86_64fromaarch64(atomic ops, byte-swap intrinsics) stay. Every other architecture branch (i386,i686,sparc,sparc64,powerpc,ppc64,ia64,mips,mips64,s390,alpha, big-endian) gets deleted.
Phase map¶
Listed in execution order. The Pandora slim-down (Phase 11) and the constant-fold (Phase 12) sit after the LTS ratchet by design — see the Status and next preamble for the rationale.
Phase |
Title |
Ubuntu |
Effort |
|---|---|---|---|
0 |
Tests in container, Zuul wiring, RST spec landed |
12.04 |
M |
1 |
Strip dead platforms; delete dead-dep plugins |
12.04 |
L |
2 |
Performance baseline harness |
12.04 |
M |
3 |
Container hygiene and Phase 0 follow-ups |
12.04 |
S |
4 |
LTS bump 14.04 |
14.04 |
M |
5 |
LTS bump 16.04 (C++11 baseline) |
16.04 |
M |
6 |
LTS bump 18.04 (Boost 1.65, OpenSSL 1.1, fs v2→v3) |
18.04 |
L |
7 |
LTS bump 20.04 (protobuf 3, C++17, PCRE2) |
20.04 |
XL |
8 |
LTS bump 22.04 (OpenSSL 3) |
22.04 |
L |
9 |
LTS bump 24.04 |
24.04 |
M |
10 |
LTS bump 26.04 (multi-arch gating, clean bindep) |
26.04 |
M |
11 |
Pandora slim-down to |
26.04 |
M |
12 |
Constant-fold the hardcoded defines into the source |
26.04 |
S |
13 |
Plugin enable-by-default sweep |
26.04 |
L |
14 |
Sphinx-only docs (Doxygen removal) |
26.04 |
S |
Dead-dep policy¶
These decisions are settled and apply across all phases:
plugin/haildb/— delete entirely in Phase 1.libhaildbis gone from modern Ubuntu; the engine is dead upstream.tokyocabinet plugin — delete entirely in Phase 1.
libtokyocabinetis unmaintained and gone from modern Ubuntu.plugin/js/(v8) — keep in tree, mark disabled. Setbuild_conditional=falseinplugin/js/plugin.iniin Phase 1. Add aplugin/js/README.revivalnote describing the intent to rewrite against modern Node/V8. Source files stay put so we know what we owe.libcloog-ppl-dev— drop from bindep.txt in Phase 1. Only needed by GCC 4.x Graphite; GCC 5+ uses ISL internally. The-floop-parallelize-allprobes inm4/pandora_warnings.m4andm4/ax_harden_compiler_flags.m4go away in the same phase (marginal optimization, not worth the noise).
Phase 0 — Tests in container, Zuul wiring, spec landed¶
Objective¶
The container currently only builds. Phase 0 wires tests into the container, sets up Zuul CI on OpenDev with the buildset-registry pattern, and lands this RST spec itself. No C++ source is touched.
Phase 0 is the foundation: every subsequent phase relies on
“podman build --target=test is green” as its definition of done,
and on Zuul to enforce that in CI.
Tasks¶
Each bullet is a candidate commit. Sequence within the phase is fluid; the test-stage Containerfile work and the Zuul work can land in parallel stacks.
Land this spec at
docs/specs/revival.rstand wire it intodocs/index.rstunder a newSpecificationssection.Create
docs/specs/index.rst.Refactor
Containerfileinto three named stages:base— apt sources + bindep install.build—autoreconf -i && ./configure && make -j$(nproc)(current behavior preserved exactly).test— installs DTR runtime deps, sets working dir to the build artifacts cache, defaultCMDruns the test entrypoint.
Add
tools/run-tests.shinvoked by the test stageCMD. Script:exports
DTR_BUILD_THREAD=$$;runs
make unitfirst (boost.test, no servers);runs
make test-drizzlewith--force --fastagainst theNORMAL_TESTSsuite list;exits non-zero on any failure
Extend
bindep.txtwith a[test platform:dpkg]profile (perl,libdbi-perl,libdbd-mysql-perl,subunit).Add
zuul.d/projects.yamlmapping the project to the four pipelines:check,vouched,gate,promote.Add
zuul.d/jobs.yamldefining the jobs listed under CI strategy — Zuul on OpenDev.Add
tools/regress.sh— a local-developer mirror of the Zuul invocations. One-command “run what CI runs.”
Local invocations (documented for contributors)¶
Inner loop — fast iteration, build only:
podman build --platform linux/amd64 --target=build -t drizzle:build .
Verification — build then run tests:
podman build --platform linux/amd64 --target=test -t drizzle:test .
podman run --rm drizzle:test
arm64 readiness check (no test gating yet, just configure+compile):
podman build --platform linux/arm64 --target=build -t drizzle:build-arm64 .
Mirror of CI:
./tools/regress.sh
Test target choice¶
make unit(boost.test,unittests/).make test-drizzlewithNORMAL_TESTS(DTR / Perl harness viatests/test-run.pl).Skipped at this phase:
kewpie,test-big,test-randgen. Too slow and/or Python-2 dependent. Revisit in Phase 13 if useful.
Container test runtime needs¶
Writable vardir under
/build(the build cache mount).DTR_BUILD_THREAD=$$for port-offset uniqueness within a single container. Server and client both live inside the container’s netns, so default networking is sufficient; no--net=host.No “drizzle” UNIX user required (the historical guard has already been removed; see
a82202956).
Done when¶
podman build --target=buildsucceeds on amd64 (regression check of current behavior).podman build --target=testsucceeds on amd64.podman run --rm drizzle:testexits 0podman build --platform linux/arm64 --target=buildsucceeds (configure + compile only; tests not gating until Phase 10).Zuul
checkpipeline runsdrizzle-lintgreen.Zuul
vouchedpipeline runsdrizzle-build-image+drizzle-unit-tests+drizzle-dtr-tests+drizzle-distcheckgreen.make htmlindocs/builds this spec without warnings.
Risks¶
DTR’s vardir lives in
/build(the cache mount), not in the read-only bind-mounted source. Confirm the cache survives betweenbuildandteststages.
Phase 1 — Strip dead platforms, delete dead-dep plugins¶
Objective¶
Mechanically delete every conditional that pertains to a platform, compiler, or architecture we will never target — while preserving the flags and defines those conditionals would have set on amd64/arm64 Linux. Delete dead-dep plugins per the dead-dep policy.
Tasks¶
Platform and compiler conditionals. Each item below is at least one commit; many are multiple commits.
m4/pandora_platform.m4: delete Solaris/Darwin/FreeBSD/mingw32 arms in bothcase "$host_os"blocks. Delete SUNCC/INTELCC detection. Hardcode the Linux-GNU branch behavior (_GNU_SOURCEdefine, glibc-style paths).m4/pandora_warnings.m4: delete INTELCC and SUNCC arms. Hardcode the GCC warnings set the Linux/GCC arm applied (-Wall -Wextra -Wformat=2 -Wmissing-declarations, etc.) as unconditionalAM_CFLAGS/AM_CXXFLAGS. Delete the-floop-parallelize-allprobe.m4/ax_harden_compiler_flags.m4: delete-floop-parallelize-allreferences. Hardcode the GCC hardening flags this macro was probing (-fstack-protector-strong,-D_FORTIFY_SOURCE=2,-Wl,-z,relro,-z,now, etc.) as unconditional flags.m4/pandora_canonical.m4: drop theforce-gcc42,PCT_FORCE_GCC42, andgnulibarms.configure.ac:39: simplifyPANDORA_CANONICAL_TARGETarguments (dropforce-gcc42).configure.ac:280-292: delete the FreeBSD post-configure echo block.Delete (verifying no live references with
grepper file):m4/pandora_ensure_gcc_version.m4(assume modern GCC)m4/pandora_have_libbdb.m4m4/pandora_have_libndbclient.m4m4/pandora_have_libhaildb.m4m4/pandora_have_libtokyocabinet.m4
m4/pandora_64bit.m4— rewrite, do not delete. Both targets are 64-bit, so the probe is unnecessary, but the behavior (definingSIZEOF_VOIDP=8,SIZEOF_LONG=8,SIZEOF_SIZE_T=8, enabling-D_FILE_OFFSET_BITS=64) must remain. Replace the macro body with unconditionalAC_DEFINElines and the appropriateAM_CFLAGS += -D_FILE_OFFSET_BITS=64. (Will fold intom4/drizzle.m4in Phase 11.)Delete the
AX_PTHREADinvocation; hardcode-pthreadintoAM_CFLAGS/AM_CXXFLAGS/AM_LDFLAGSandAC_DEFINE([HAVE_PTHREAD],[1]).Delete the
gl_VISIBILITYinvocation; hardcode-fvisibility=hidden -fvisibility-inlines-hiddenintoAM_CXXFLAGSandHAVE_VISIBILITY=1.AC_CHECK_FUNCS/AC_CHECK_HEADERSaudit. This is itself a stack of small commits — one probe (or one tight logical group) per commit. For every probe of a POSIX/glibc-guaranteed function or header (memmove,strerror,inet_ntoa,<stdint.h>,<inttypes.h>,<cstdint>,<unordered_map>, etc.):delete the probe; and
delete the corresponding
#ifdef HAVE_*in source (preferred, same commit); orif the
#ifdefis widely scattered,AC_DEFINEthe symbol unconditionally for now and remove the#ifdefs in a follow-up commit.
AC_CHECK_SIZEOF(off_t|size_t|long long)— delete; hardcode to 8.DRIZZLE_STACK_DIRECTION— delete; hardcode “grows down”.
Architecture handling (multi-arch — amd64 + arm64).
In
m4/pandora_platform.m4(or wherever host CPU is examined): keep branches distinguishingx86_64fromaarch64(atomic ops, byte-swap intrinsics, cache-line size if used). Delete branches fori386,i686,sparc,sparc64,powerpc,ppc64,ia64,mips,mips64,s390,alpha, etc. Hardcode little-endian; delete any big-endian conditional code paths.Audit source for x86-specific intrinsics (
__builtin_ia32_*,_mm_*, SSE/AVX) and x86 inline asm. List any findings in the Appendix — Multi-arch hazards appendix so later phases know where aarch64 paths are needed. Don’t fix in Phase 1 unless trivial. The Phase 1 audit’s scope turned out to be narrower than its “no hazards found” wording suggested — see the multi-arch hazards appendix for the rewritten honest result and the remaining queue.
Plugin and dependency deletions. Each is its own commit:
Delete
win32/directory.Delete
plugin/haildb/(or the actual haildb plugin path).Delete the tokyocabinet plugin.
Set
build_conditional=falseinplugin/js/plugin.iniand addplugin/js/README.revivaldescribing the modern-V8/Node rewrite intent. Leave source files alone.Drop
libcloog-ppl-devfrombindep.txt.
Done when¶
configure.ac carries no dead-platform or dead-architecture
conditional:
grep -nE 'solaris|freebsd|mingw32|darwin|SUNCC|INTELCC|TARGET_OSX|cloog' configure.ac
grep -nE 'i386|i686|powerpc|ppc64|sparc|mips|s390|ia64|BIG_ENDIAN' configure.ac
Both return empty.
The grep is scoped to configure.ac deliberately. The first-party
m4/pandora_*.m4 macros still carry Solaris/Intel/PowerPC arms at
the close of Phase 1; they are removed as each file is folded into
m4/drizzle.m4 in Phase 11 — writing the macro afresh drops the dead
arms without a throwaway in-place edit first. The vendored m4 files
(boost.m4, the gettext set, ax_pthread.m4) keep their
portability code: they are upstream and regenerated, not hand-edited.
The ≥40% wc -l m4/*.m4 reduction is consequently a Phase 11
outcome, measured there.
Phase 0 tests still pass on amd64.
podman build --platform linux/arm64 --target=buildstill gets through./configurecleanly. Test failures on arm64 are recorded in Appendix — Multi-arch hazards but not gating until Phase 10.
Risks¶
Removing
gnulibmay surface latent dependencies. Land that removal in its own commit so a revert is cheap.m4/pandora_extensions.m4providesAC_USE_SYSTEM_EXTENSIONSwrapping. Verify it isn’t load-bearing before deletion.
Phase 2 — Performance baseline harness¶
Objective¶
Stand up a deterministic, hardware-independent performance measurement before any code is restructured, so every later phase can be judged against a frozen baseline. We have no dedicated performance hardware and CI runs on shared nodes, so wall-clock time is meaningless. Instead, count work synthetically: callgrind simulates execution and counts instructions, which is reproducible run-to-run and identical on any host.
This phase ships only measurement infrastructure — it changes no server code. It exists so that subsequent phases have a signal.
Tasks¶
Add
valgrindtobindep.txtunder a new[perf platform:dpkg]profile (callgrind,massifandcallgrind_annotateall ship with it). Add the PerlDBI/DBDpackagessql-benchneeds under the same profile.Workload: drive
tests/test_tools/sql-benchagainst a drizzled instance — it already carries a drizzle server profile. Pin the dataset and iteration counts; single connection. If theDBDpath against the MySQL-protocol port proves unworkable on Precise, fall back to a bespoke deterministic SQL workload underperf/; record which path was taken in the commit message.tools/perf.sh— install Drizzle and the workload driver, launch drizzled undervalgrind --tool=callgrind --cache-sim=yes --branch-sim=yes, run the workload, and parsecallgrind_annotateinto a JSON metrics file: total instructions (Ir), an estimated-cycles figure, and the L1-miss, LLC-miss and branch-mispredict totals. The whole process is instrumented — boot included — because toggling instrumentation mid-run needs ptrace, which the build container’s kernel restricts; server boot is a stable constant, so it does not disturb deltas.Second pass over the same workload under
valgrind --tool=massiffor peak heap.Record
size(1)output fordrizzledand every plugin.so— code-size tracking is free and tracks toolchain bloat.Commit captured numbers under a
perf/directory in the tree.tools/perf.shwrites the current run there and diffs it against the committed baseline.Zuul: add a
drizzle-perfjob to thevouchedandgatepipelines runningtools/perf.shon every commit. Non-gating — it reports the delta against baseline; it does not fail the build.At the close of every later phase, run
tools/perf.shby hand and commit the numbers asperf/<release>.json—perf/14.04.jsonwhen Phase 4 lands,perf/16.04.jsonfor Phase 5, and so on.perf/baseline.json(the 12.04 result) is never overwritten. The accumulating set of per-release files is the performance time series, all in one place — no external dashboard. Once the revival reaches 26.04 we revisit how to re-baseline.
Done when¶
tools/perf.shproduces its JSON metrics file end to end and diffs it against the baseline. Instruction count is reproducible to within a low-single-digit percent — drizzled is multithreaded and callgrind sums every thread, so background-thread work sets a ~2% noise floor. The job is for catching larger shifts; treat sub-~3% deltas as noise. (Driving the floor down — per-thread collection, quieter background plugins — is a later refinement.)A Phase 1 baseline is committed under
perf/.callgrind and massif are both available in the container via
bindep.txt.The
drizzle-perfjob runs invouchedandgate.
Risks¶
sql-benchis Perl/DBI; theDBDpath against drizzle’s MySQL-protocol port may not work cleanly on Precise. The fallback is a bespokeperf/workload — circle back ifDBDfights us.callgrind is a ~20–50× slowdown and the job runs per commit. Keep the workload small enough that the
vouched/gatepass stays in single-digit minutes — run a subset ofsql-bench, not all of it.Across an LTS bump valgrind itself changes, which slightly shifts the instruction count; within a phase it is constant.
drizzled is multithreaded and callgrind sums every thread, so background-thread work (InnoDB and friends) gives the instruction count a ~2% run-to-run noise floor. The harness lands with that understood; tightening it is future work.
Non-deterministic SQL (
NOW(),RAND(),UUID()) would destroy reproducibility — the curated workload uses none.
Phase 3 — Container hygiene and Phase 0 follow-ups¶
Objective¶
Land the parts of the Phase 0 test-image contract that weren’t
actually realized (built tree in the image layer, runtime CMD,
per-arch cache isolation, m4/drizzle.m4 in EXTRA_DIST),
tighten dependency hygiene, and mirror this spec’s decisions into
the project’s orientation docs and source-comment hygiene. The phase
touches only build-system, container, and documentation files — no
C++ source changes.
This phase exists because every subsequent phase’s “every commit
green” invariant relies on podman run drizzle:test actually
running tests against the just-built tree. Today it doesn’t.
Tasks¶
Container hygiene (each item is a candidate commit, ordered):
Add
m4/drizzle.m4toEXTRA_DISTinMakefile.am. Lands first — protectsmake distcheckwhile the rest of the stack reshuffles the container build.Make the build cache per-arch:
id=drizzle-build-${TARGETPLATFORM}in the three--mount=type=cachelines ofContainerfile. amd64 and arm64 stop reusing each other’s object files and configure results.Materialize the built tree into the image layer (
cp -auout of the cache mount inside thebuildstage); repointtestandperfstages at the in-image path; addCMD ["tools/run-tests.sh"]to theteststage sopodman run drizzle:testruns tests at runtime; drop the build-timeRUN tools/run-tests.sh. One commit — the four pieces only make sense together.Confirm
tools/regress.shruns the runtime contract end to end (podman run drizzle:regress-test, no--net=host); align help text if needed.Move
rabbitmq-serverfrom[compile platform:dpkg]to[test platform:dpkg]inbindep.txt. Safe only after the test image carries its own tree and installs thetestbindep profile.Pin the perf-harness CPAN fetch in
ContainerfilewithADD --checksum=sha256:<pin>for theDBD::drizzletarball. Remote fetch + checksum is the preferred pattern — vendoring is deliberately avoided.Verify the cache reconfigure behavior. The current
[ ! -f Makefile ]guard exists so a no-op iteration doesn’t re-runautoreconf -i && ./configure(which would churnconfig.hand discard the build cache on every build). The expectation is that the automake-generatedMakefilealready detects edits toconfigure.ac/m4/*.m4/Makefile.amand re-runs the right pieces from inside the cache. Verify during the next test pass; only add a smarter cache-bust (hash the build-system inputs into a stamp file, compare on entry, runautoreconf -i && ./configureon mismatch) if the self-regen turns out to be unreliable across the cache mount. Do not drop the guard.
Companion doc and convention cleanup (separate sub-stack — mirror this spec’s decisions into the orientation docs and source-comment hygiene):
Update
AGENTS.mdto match the spec: drop--net=hostfrom the verification example, refresh the test-runtime contract line, replace any hardcoded plugin count with phrasing.Rewrite
README.rstso the front matter routes contributors to theContainerfile/bindep.txt/tools/regress.shflow. No Docker, no PPAs, no source-install. Deeper docs pruning stays in Phase 14.Clean up the gravestone comments listed in the Foundational principles “No gravestone comments” violation list above — rewrite as forward-looking constraints, or delete.
future-zuul.d/projects.yamlcurrently schedules onlydrizzle-build-image(amd64). Either add a scheduleddrizzle-build-image-arm64per the CI strategy section, or drop a TODO comment naming it as a known gap to close at activation time.
Done when¶
podman build --target=test -t drizzle:test .followed bypodman run --rm drizzle:testruns tests and exits 0; nopodman runinvocation in the spec,AGENTS.md, ortools/regress.shuses host networking.make distcheckpasses.amd64 and arm64 builds reuse nothing from each other’s cache.
grep -niE 'docker|dockerfile' README.rstreturns empty.No gravestone comments remain at the three sites listed under Foundational principles.
Risks¶
The reconfigure-behavior verification may find that automake’s self-regen doesn’t fire reliably across the cache mount, in which case we add the stamp-based cache-bust noted above. Dropping the
[ ! -f Makefile ]guard outright is not the fix — it makes the cache useless.The
rabbitmq-serverprofile move must land after the test image actually installs thetestbindep profile; reordering breaks DTR.
Phases 4–10 — LTS bump template¶
Each LTS bump follows the same shape. Sub-phases per LTS are listed afterward.
Template tasks¶
Bump the
FROMline of theContainerfilebasestage. Base images are pulled from quay.io rather than docker.io so that Zuul never trips docker.io’s pull rate limits:Through Ubuntu 20.04, use
quay.io/inaugust/unsafe-old-distro-danger:X.04— mirrors of the EOL Ubuntu LTS images, with/etc/apt/sources.listalready repointed atold-releases.ubuntu.comfor the releases that need it. This is why thebasestage carries noold-releasessed.From Ubuntu 22.04 on, use
quay.io/opendevmirror/ubuntu:X.04, the OpenDev infrastructure mirror of the still-supported images.
Both registries publish
linux/amd64andlinux/arm64.Update
bindep.txt: replace[platform:ubuntu-PREVIOUS]selector lines with[platform:ubuntu-CURRENT], adjusting versioned package names (boost, protobuf, etc.). One commit.Build on amd64:
podman build --platform linux/amd64 --target=build \ -t drizzle:phaseN-amd64-build .
Triage compile breakage. Fix code.
-Wno-xxxpermitted only as last resort, with a written rationale in the commit message.Test on amd64:
podman build --platform linux/amd64 --target=test \ -t drizzle:phaseN-amd64-test . podman run --rm drizzle:phaseN-amd64-test
Fix test failures.
Build on arm64 (build-only readiness until Phase 10):
podman build --platform linux/arm64 --target=build \ -t drizzle:phaseN-arm64-build .
Must succeed. Test runs on arm64 are encouraged for local validation but not gating until Phase 10, so no
--target=testbuild and no arm64testtag exist for Phases 4–9.make distcheckmust pass on amd64.The per-arch tags from steps 3–5 are the artifacts the
promotepipeline later pushes (re-tagged with the merge SHA + phase name):drizzle:phaseN-amd64-build,drizzle:phaseN-amd64-test,drizzle:phaseN-arm64-build. Phase 10 addsdrizzle:phase10-arm64-testto the set when arm64 becomes test-gating.
Phase-specific notes¶
Phase 4 — Ubuntu 14.04¶
Lightest LTS bump. Boost 1.46 → 1.54; protobuf still 2.x; OpenSSL still 1.0. Mostly warning-flag drift.
Phase 5 — Ubuntu 16.04 (C++11 baseline)¶
Add
AX_CXX_COMPILE_STDCXX([11],[noext],[mandatory])toconfigure.ac— one commit.Delete now-redundant C++11-capability m4 files (
pandora_check_cxx_standard.m4,pandora_shared_ptr.m4,pandora_stl_hash.m4,ax_cxx_compile_stdcxx_0x.m4,ax_cxx_header_stdcxx_98.m4) — one commit per file.Mechanical rename
boost::shared_ptr→std::shared_ptracrossdrizzled/. Stack of small commits, one per directory or logical unit so each stays green.Mechanical rename
boost::unordered_map→std::unordered_mapsimilarly.
Phase 6 — Ubuntu 18.04 (Boost 1.65, OpenSSL 1.1)¶
First real friction phase. Sub-stacks:
Audit
#include <boost/...>acrossdrizzled/andplugin/. Replaceboost/foreach.hppwith C++11 range-for (one commit per consumer).Migrate
boost::filesystemv2 API to v3. Dedicate this to its own contributor; it’s the worst single transition of Phase 6.OpenSSL 1.1 makes
SSL_CTXand friends opaque. Replace direct field access with accessor functions. Auditplugin/auth_*,client/,drizzled/.Add
-Wimplicit-fallthroughannotations or[[fallthrough]];.
Phase 7 — Ubuntu 20.04 (protobuf 3, C++17, PCRE2)¶
Hardest phase. Four sub-stacks; the order below is the recommended sequencing — the compiler-mode flip lands first so the C++17 sweep has something to compile against.
7.0: Enable C++17 in the build. Set
AX_CXX_COMPILE_STDCXX([17],[noext],[mandatory])(or the equivalent that replacesPANDORA_CHECK_CXX_STANDARD) and confirmpodman build --target=teststays green before any C++17-only source change lands. Mandatory: no ad-hoc-std=c++17introduction inside a later patch.7a: protobuf 2 → 3. Regenerate
.pb.cc/.pb.hat configure time; stop versioning generated code. Update API uses (set_allocated_*semantics;ReflectionAPI churn; arena allocation).7b: libpcre1 → libpcre2. Rewrite
m4/pandora_have_libpcre.m4(or its replacement inm4/drizzle.m4) toPKG_CHECK_MODULES([PCRE2],[libpcre2-8]). Auditplugin/regex_policy/and any other direct PCRE callers.7c: C++17 sweep.
std::auto_ptr→std::unique_ptr;std::random_shuffle→std::shuffle+std::mt19937;registerkeyword removed;throw()→noexcept.
Bump BOOST_REQUIRE([1.46]) to BOOST_REQUIRE([1.71]) in
configure.ac.
Phase 8 — Ubuntu 22.04 (OpenSSL 3)¶
Switch the
Containerfilebaseimage fromquay.io/inaugust/unsafe-old-distro-dangertoquay.io/opendevmirror/ubuntu:22.04. 22.04 is still supported, so the OpenDev mirror carries it and its apt sources need no rewrite.Migrate direct
SHA1_*/MD5_*/HMAC_*calls toEVP_*equivalents (plugin/md5/,plugin/auth_http/,drizzled/sha1.ccif present).Either fix every
OPENSSL_NO_DEPRECATED_3_0warning or accept-Wno-deprecated-declarationsin a single compilation unit (auth code), explicitly noted in commit message.Bump Boost requirement to 1.74.
Phase 9 — Ubuntu 24.04¶
Mostly free. GCC 13 / Boost 1.83 -Werror casualty sweep.
Phase 10 — Ubuntu 26.04 (final landing)¶
We should be able to test building directly on the laptop.
We may consider adding Fedora support to bindep.txt at this point. Maybe.
If we have running zuul jobs:
arm64 becomes fully gating.
make test-drizzlemust pass on both architectures. Extend step 5 of the LTS bump template to also build--target=teston arm64 and to run the resultingdrizzle:phase10-arm64-testimage; fix arm64-specific test failures accumulated during Phases 4–9.Make multi-node jobs using buildset registry for coordiation to do native arm64 and amd64 builds, then produce a final manifest like:
podman manifest create drizzle:26.04 podman manifest add drizzle:26.04 drizzle:phase10-amd64-test podman manifest add drizzle:26.04 drizzle:phase10-arm64-test
Phase 11 — Pandora slim-down to m4/drizzle.m4¶
Objective¶
Excise the Pandora macro layer as a layer while preserving every
piece of behavior it provides. End state: a single m4/drizzle.m4
(~400 lines) plus a small number of upstream third-party m4 files
(boost.m4, the kept-deliberately pandora_plugins.m4,
gettext machinery).
This phase runs on the 26.04 toolchain rather than the 12.04 one
because the LTS ratchet ahead of it brings modern pkg-config, Boost,
OpenSSL, and protobuf — converting the library-presence macros to
PKG_CHECK_MODULES is cleaner against the modern stack than against
the 12.04 readline-without-pc situation that motivated keeping
pandora_have_libreadline.m4 around. Partial work landed earlier
(DRIZZLE_BUILD_SETUP skeleton; several macros folded into
m4/drizzle.m4) remains; this phase resumes from that state.
Tasks¶
Several build-setup macros have already folded into
m4/drizzle.m4 (version, C++ standard, dtrace, platform, optimize,
warnings, VC info) and DRIZZLE_BUILD_SETUP is in place at
configure.ac:38. The remaining work:
Library-presence macros — convert to ``PKG_CHECK_MODULES``, one commit each, protobuf first.
pandora_have_protobuf.m4AC_REQUIREsAX_PTHREAD, which is the last live caller of the pthread probe; replacing it withPKG_CHECK_MODULESremovesAX_PTHREADfrom the build entirely. Thenlibzandlibssl.libpcrealready switched toPKG_CHECK_MODULESduring Phase 7 because the PCRE2 API migration needed the package’s compiler flags.libdlbecomesAC_SEARCH_LIBS([dlopen],[dl])—dlopenis in glibc and there is nolibdl.pcon any release.readlinefinally converts toPKG_CHECK_MODULESas well now thatreadline.pcis universally available on the 26.04 base. Each replacement preserves the variables theMakefile.amfiles consume —$(LIBZ),$(LIBSSL),$(LIBPCRE)/$(LTLIBPCRE),$(LIBPROTOBUF)/$(LTLIBPROTOBUF),$(LIBDL_LIBS)— assigned from the*_LIBSpkg-config output, plus theHAVE_LIB*config.hdefines.bzr/svn/hg version-control arms. Commit
63ebbc28claims this strip; in realitym4/drizzle.m4:492-593still definesPANDORA_TEST_VC_DIRandPANDORA_BUILDING_FROM_VCwith all four arms and still shells out tobzr. Land the actual deletion: keep only the git arm; thebzr revno/bzr nick/bzr logextraction and the svn/hg branches go.LP64 sizes in top-level ``configure.ac`` are only partially hardcoded. Add
SIZEOF_VOIDP=8andSIZEOF_LONG=8next to the existingSIZEOF_OFF_T/SIZEOF_SIZE_T/SIZEOF_LONG_LONGAC_DEFINElines.``PANDORA_`` → ``DRIZZLE_`` rename, landed together with
config/pandora-plugin’s emitted standalone-plugin template update so out-of-tree plugin generation keeps working through the rename. Macros now living inm4/drizzle.m4(PANDORA_MSG_ERROR,PANDORA_WARNINGS,PANDORA_PLATFORM,PANDORA_VERSION,PANDORA_OPTIMIZE,PANDORA_VC_INFO_HEADER, etc.) all rename, with call sites inconfigure.acupdated; the configure summary atconfigure.ac:243still printspandora-build version— fix in the same stack. Land after the library-macro conversion so the macro set is stable. Skip the deliberately-keptpandora_plugins.m4and the plugin-dependencyhave-libmacros still called byplugin/*/plugin.ac.Revisit ``config/pandora-plugin`` as a generator. The Python 2 script still earns its keep during the LTS ratchet because changing the plugin enumeration machinery would be a structural rewrite. Once Phase 11 owns the Pandora cleanup directly, replace it with a smaller maintained generator or a generated-file-free build description rather than continuing to carry Python as the default answer.
Delete the now-unused ``m4/pandora_*.m4`` files as each one’s last caller goes away. One commit per file.
InnoDB is an upstream-merge surface — do not touch. Earlier drafts of this phase contemplated stripping
AC_CHECK_SIZEOFprobes and dead-platform arms fromplugin/innobase/plugin.ac; that strip is withdrawn. Future MySQL / MariaDB cherry-picks depend on InnoDB’s cross-platform arms (and their attendant configure/source symbol mismatches) staying mergeable. The InnoDB issues are recorded in Appendix — C++ and threading correctness debt as known latent, deliberate non-fixes.
Done when¶
The Pandora build-setup layer is gone:
m4/drizzle.m4is the only orchestration file, and the survivingpandora_*.m4files arepandora_plugins.m4plus the plugin-dependencyhave-libmacros still called byplugin/*/plugin.ac(libaio,libcurl,libevent,libgearman,libldap,libmemcached,libv8, flex). Those retire in Phase 13 with the plugin sweep — Phase 11 does not reach the original “≤2 files” target, and is not meant to.plugin/innobase/is intentionally untouched — its cross-platform arms stay so future MySQL / MariaDB cherry-picks remain mergeable.configure.acis under 250 lines.grep -rnE 'solaris|freebsd|SUNCC|INTELCC|i386|powerpc|sparc'over the first-party m4 (everything butboost.m4and the vendored gettext set) returns empty.wc -l m4/*.m4shows a substantial drop versus the Phase 0 baseline. The original ≥40% figure assumed the plugin have-lib macros also went; with those correctly deferred to Phase 13, report the actual figure rather than forcing it.Phase 0 tests still pass on amd64.
./configuresucceeds on arm64.
Risks¶
pandora_plugins.m4is the most opaque file in the layer — it generatesam__plugin_LISTand the load-list. Treat it as load-bearing infrastructure. Do not rewrite; verify it still works after surrounding deletions.
Phase 12 — Constant-fold the hardcoded defines into the source¶
Objective¶
Phase 1 replaced a raft of autoconf probes with fixed AC_DEFINE
constants, and Phase 11 adds more as it moves to
PKG_CHECK_MODULES. A #define whose value can no longer vary
makes every #ifdef and #if that tests it dead-reckonable: the
preprocessor branch is now always-taken or never-taken, and any C/C++
if written against the value is a constant condition.
Phases 1 and 11 stop at the configure layer. Phase 12 follows each
hardcoded symbol into the source and removes the now-pointless
indirection — delete the dead preprocessor branch, inline the
constant, and simplify whatever conditional logic the old variability
forced. A static define still threaded through #ifdefs is only
half-stripped; this phase finishes the job, in one pass over both
phases’ constants.
This is a source-only phase; it changes no build behavior.
Tasks¶
Each symbol below is at least one commit. Audit every consumer
(grep the symbol across drizzled/, client/, plugin/,
libdrizzle*), then collapse.
STACK_DIRECTION(always-1).drizzled/check_stack_overrun.ccderives a constant from it and branches on that constant; both the define-test and the branch fold away, simplifying the function body.HAVE_PTHREAD(always1). Delete the#ifdef HAVE_PTHREADguards; the guarded code is unconditional.HAVE_VISIBILITY(always1). Collapse the#if HAVE_VISIBILITYladders in thevisibility.hheaders to their visibility-supported branch.TARGET_OS_LINUX(always1). Delete the#ifdefguards indrizzled/definitions.handlibdrizzle/conn.cc; the Linux branch is unconditional.SIZEOF_OFF_T/SIZEOF_SIZE_T/SIZEOF_LONG_LONG(always8). Fold any#if SIZEOF_* == nselection to the 8-byte arm.Endianness.
WORDS_BIGENDIANis now never defined; delete the big-endian arm of every#ifdef WORDS_BIGENDIANso only the little-endian path remains.The
HAVE_LIB*symbols Phase 11’sPKG_CHECK_MODULESswitch left as foregone conclusions, and anyHAVE_*theAC_CHECK_FUNCS/AC_CHECK_HEADERSaudit chose toAC_DEFINEunconditionally rather than strip in place.
When a folded symbol has no consumer left at all, drop the
AC_DEFINE too: it existed only to be tested.
Done when¶
No
#ifdef/#ifin first-party source tests a symbol whose configure value is now a fixed constant.Phase 0 tests still pass on amd64.
size(1)ofdrizzledis unchanged or smaller — this phase only removes dead branches.
Risks¶
A symbol tested in both a live and a dead branch can hide a behavior change if the wrong branch is kept. Cross-check each collapse against the value the configure layer actually hardcoded.
Phase 13 — Plugin enable-by-default sweep¶
Objective¶
Every plugin in plugin/ builds on the 26.04 target by default.
bindep.txt covers every plugin’s dep unconditionally. No
build_conditional= line survives (modulo the v8 plugin, which
remains opt-out pending Node-based rewrite).
Tasks¶
Build every in-tree plugin on 26.04 with the default
configureinvocation. Categorize each failure:Easy fix (warning flag, header path) — fix in this phase, one commit per plugin.
Hard fix (dead upstream API but modern alternative exists) — port to the modern API, separate commit per plugin.
Hopeless (truly dead upstream, no modern replacement) — delete the plugin entirely.
Expand
bindep.txtwith every required dep, unconditionally.Delete every
build_conditional=line fromplugin/*/plugin.iniexcept forplugin/js/plugin.ini. Each deletion is its own commit (after proving the condition is always true on the 26.04 target).
Done when¶
grep -l 'build_conditional' plugin/*/plugin.ini
returns only plugin/js/plugin.ini.
makebuilds every other plugin.make test-drizzlepasses.
Optional: split production and test-client images¶
The user’s stated target topology for CI:
“A job builds a production container, then a second job runs all the tests against a server running from the container.”
If appetite exists in Phase 13, split the Containerfile into:
productionstage —drizzledbinary + minimal runtime deps, no test harness, no perl.test-clientstage — DTR/perl tooling but nodrizzled.
Then drizzle-dtr-tests in CI runs the production image as a
long-running container (podman run -d), and the test-client image
drives DTR against it via --network=container:<prod> or a podman
pod. This gives us the property that the image we ship is the image
we test.
Not gating for Phase 13 completion; tracked under Future work.
Phase 14 — Sphinx-only docs¶
Objective¶
Delete Doxygen entirely. Sphinx remains the only documentation toolchain. Existing 65 RST files are the foundation.
Tasks¶
Delete
docs/Doxyfile.Delete
plugin/innobase/Doxyfile.Remove
AC_CHECK_PROGS([DOXYGEN],[doxygen])fromconfigure.ac.Update
docs/include.amto drop Doxygen rules and theSPHINX_BUILDDIRclean-local Doxygen-related entries.Migrate any salvageable architectural commentary from Doxygen comments into RST under
docs/contributing/(or a newdocs/internals/).Drop the Doxygen entry from
bindep.txtif present.Sweep the installing/contributor docs for stale install paths (distro packages, PPAs, source-install,
./bootstrap) and reroute to the container-firstContainerfile/bindep.txt/tools/regress.shflow. Phase 3 fixes the README front matter; this finishes the rest.
CI strategy — Zuul on OpenDev¶
Activation status¶
The Zuul pipeline files described in this section live under
future-zuul.d/ and are not currently active — they are inert
scaffolding waiting on OpenDev Zuul tenant registration and the
referenced playbooks. When activated, the files move to zuul.d/
and the same definitions take effect.
Until then: amd64 build+test gating once activated; arm64 build-only
readiness until Phase 10, at which point arm64 becomes test-gating
too. future-zuul.d/projects.yaml currently schedules only
drizzle-build-image (amd64); drizzle-build-image-arm64 is a
known gap to close at activation time and is tracked in
Phase 3.
Pipeline model¶
CI runs on OpenDev Zuul. Pipeline mapping:
check — cheap, fast-feedback jobs only: linting,
autoreconfsyntax,./configuredry-run, docs build. Runs on every patchset, unreviewed.vouched — full build + test. Runs only after the OpenDev AI review agent has reviewed the change. This is where the heavy work lives — container build, full DTR run,
make distcheck, multi-arch builds.gate — identical to
vouched(re-runs at merge time to catch races).promote — after merge, tags and pushes the final container image to the permanent registry.
Everything must always pass. There is no “soft” job; flaky tests get fixed.
Job design (buildset-registry pattern)¶
We follow the canonical OpenDev container-build pattern: one job
builds the image into a per-buildset intermediate registry; downstream
jobs in the same buildset pull from that registry. Tests run against
the exact same image artifact that promote pushes, not a
re-build.
Job definitions live in zuul.d/jobs.yaml. Pipeline mapping lives
in zuul.d/projects.yaml.
Jobs:
drizzle-lint—checkpipeline only. Bare nodeset, no container.autoreconf -i,./configure --no-create, docs build smoke. ~2 minutes.drizzle-build-image—parent: opendev-build-container-image. Builds thetestContainerfile stage into the buildset registry. Runs once per arch (linux/amd64,linux/arm64) via Zuul’s per-arch nodesets, producing two tags in the buildset registry.drizzle-unit-tests—parent: opendev-buildset-registry-consumer. Pulls the image from the buildset registry; runspodman run --rm <image> make unit. Depends ondrizzle-build-image.drizzle-dtr-tests— same parent. Pulls the image; runsmake test-drizzle. Depends ondrizzle-build-image.drizzle-distcheck— runsmake distcheckagainst the built tree. Same parent pattern.drizzle-promote-image—parent: opendev-promote-container-image. Only in thepromotepipeline. Re-tags the buildset-registry image into the permanent registry under the merge-commit SHA andlatest.
Pipeline composition:
check—drizzle-lint.vouchedandgate—drizzle-build-image(amd64 + arm64),drizzle-unit-tests(both arches),drizzle-dtr-tests(both arches),drizzle-distcheck(amd64 only).promote—drizzle-promote-image.
Per-phase image promotion¶
After each phase merges, the promote pipeline tags the image with
the phase name (e.g. drizzle:phase1-strip,
drizzle:phase4-ubuntu1404) in addition to the SHA. This gives us a
permanent regression archive: any future change can
podman run drizzle:phaseN make test-drizzle to verify it doesn’t
regress prior phases.
Appendix — Multi-arch hazards¶
A running list, populated during Phase 1’s architecture audit and extended through Phases 4–9. Each entry describes an x86-specific or endianness-sensitive construct in the source and a sketch of the aarch64 fix.
Phase 1 audit scope (honest restatement). The original audit
grepped only drizzled/, client/, and libdrizzle* for the
narrow construct set __builtin_ia32_* / _mm_* / SSE-AVX
*intrin.h / __asm / asm volatile / rdtsc / cpuid
and reported “no hazards found.” That result was correct for that
scope; it was not a sweep of all multi-arch hazards in the tree. The
grep did not cover plugin/, did not check for __i386__ /
WORDS_BIGENDIAN / pthread-yield / SIZEOF_* conditionals, and
did not look at unaligned-access fast paths or release-store
correctness. Items below were surfaced by a broader pass.
plugin/innobase/ is out of scope for this appendix per
Appendix — C++ and threading correctness debt — InnoDB is treated as an upstream-merge
surface, so its existing cross-platform arms stay untouched and
its arm64 behavior travels with the upstream code we cherry-pick.
Hazards to address (each gets a triage during a Phase that naturally touches the file, or earlier if a contributor wants to land it standalone):
drizzled/korr.h:31-58—__i386__-gated unaligned-access fast path. aarch64 silently drops into the portable byte-by-byte branch, which works but loses the optimization. Decision: convert to__attribute__((aligned(1)))/__builtin_memcpy-based unaligned load that the compiler emits well on both arches, or delete the fast path and rely on the portable branch.drizzled/korr.h:88-93,plugin/myisam/myisampack.h:28-41,libdrizzle-1.0/constants.h:512-523— signed byte-unpack macros left-shift signed bytes into high bits, which is C++ undefined behavior. See Appendix — C++ and threading correctness debt for the rewrite plan; the arm64 angle is that newer compilers on the ratchet can optimize around the UB and produce a different result per arch.drizzled/atomics.hplusdrizzled/atomic/gcc_traits.h:81-85—store_with_releaseis implemented as a plain assignment through avolatilepointer, which does not provide release ordering on aarch64. See Appendix — C++ and threading correctness debt.drizzled/session.h:512anddrizzled/drizzled.cc:231-233— cross-thread kill/shutdown state usesvolatileinstead of atomics. Often masked on x86; not on arm64. See Appendix — C++ and threading correctness debt.drizzled/field/*,libdrizzle/sha1.cc,plugin/myisam/*— broader pass owed. Grep forWORDS_BIGENDIAN,__i386__,__x86_64__,SIZEOF_*conditionals, pthread-yield wrappers, byte-swap intrinsics. Populate this list as the audit lands.
Appendix — C++ and threading correctness debt¶
Items a broader review surfaced that are real but better caught and fixed when the LTS-bump compiler ratchets (Phases 6, 7, 9) raise them as warnings or errors. This appendix is the discovery trail, not a parallel work plan to execute now. A contributor with appetite can land any of them as a standalone commit; otherwise the natural ratchet delivers them in context.
Signed byte-unpack shift UB —
drizzled/korr.h:88-93,plugin/myisam/myisampack.h:28-41,libdrizzle-1.0/constants.h:512-523. The unpackers left-shift signed (or signed-promoted) byte values into high bits, which is C++ undefined behavior. Rewrite as unsigned accumulation with an explicit final cast for the signed-result variants; add unit coverage for high-bit 2-, 3-, and 4-byte signed and unsigned decoders.Cross-thread ``volatile`` state —
drizzled/session.h:512(kill state),drizzled/drizzled.cc:231-233(select-loop and shutdown globals).volatileis not synchronization in C++; these are data races that x86 has masked in practice. Convert to real atomics or to existing mutex-protected state; add stress coverage for concurrentKILLand shutdown paths.``atomic<T>::operator=`` is not a release store —
drizzled/atomic/gcc_traits.h:81-85.store_with_releaseis implemented as plain assignment through avolatilepointer, which provides no release ordering on aarch64 and races readers that expect the wrapper to provide atomic semantics. Use__atomic_store_n(..., __ATOMIC_RELEASE)(with a documented fallback for the 12.04 compiler if needed); extendunittests/atomics_test.ccbeyond single-thread arithmetic.``logging_query`` PCRE2 regex replacement lock —
plugin/logging_query/logging_query.cc. Phase 7’s PCRE2 port uses a coarse mutex around compiled-regex replacement and matching so runtime sysvar updates cannot race readers that still hold the old compiled pattern. After the LTS ratchet reaches current toolchains, revisit this with an ownership model that lets readers match without serializing on the update lock.``Join`` cloned with ``memcpy`` —
drizzled/join.cc:1289-1292.Joinis noncopyable and owns non-trivial members, so the rawsizeof(Join)copy is object-lifetime UB and will trip-Wclass-memaccesson a modern compiler. Replace with an explicit snapshot/restore object, or save and restore only the fields needed for temporary-table state.``COM_PROCESS_KILL`` payload byte order — see Appendix — Investigation backlog; tracked there because it needs a behaviour test before any patch.
json_server lifecycle regression test owed —
plugin/json_server/json_server.cc:697-704. The pushed fix signals once and joins every worker; the design is plausible but has no DTR test pinning the behavior. Add a plugin-level test that startsjson_serverwithmax_threads > 1and exercises clean shutdown or plugin unload.
InnoDB-related entries below are deliberate non-fixes per the upstream-merge policy (see Phase 3 — Container hygiene and Phase 0 follow-ups and Phase 11 Done-when). They are listed so future contributors recognise them as known and intentional, not oversights:
InnoDB configure/source symbol mismatch.
plugin/innobase/plugin.ac:91-93definesHAVE_ATOMIC_PTHREAD_T, butplugin/innobase/include/os0sync.hchecksHAVE_IB_ATOMIC_PTHREAD_T_GCCandHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS. Similarly,plugin/innobase/plugin.ac:164-166definesIB_HAVE_PAUSE_INSTRUCTIONwhileplugin/innobase/include/ut0ut.hchecksHAVE_PAUSE_INSTRUCTION/HAVE_FAKE_PAUSE_INSTRUCTION. The configure probes have been silently dead for ~15 years; the source already falls through to the portable branch. Do not fix in-tree — the cross-platform arms are MySQL-shaped and the right fix arrives via the next InnoDB cherry-pick from upstream.
Appendix — Investigation backlog¶
Items that are probably bugs but need a test or a protocol-spec read before any patch is justified. Drive each one to a yes/no answer; convert to a normal Phase task or close with a note.
``COM_PROCESS_KILL`` payload byte order.
plugin/mysql_protocol/mysql_protocol.cc:243-245maps MySQL command12to the internalCOM_KILLwithout translating the payload.drizzled/sql_parse.cc:246-258reads the internal payload as a four-byte value and converts it withntohl, whilelibdrizzle/conn.cc:730-732sends native kill ids withhtonl. MySQL protocol integer payloads are documented as little-endian. Native Drizzle clients and MySQL-protocol clients therefore appear to disagree about byte order for the same internal command. Tasks:Confirm the MySQL protocol spec’s payload byte order for command
12.Write a raw-protocol DTR test that sends
COM_PROCESS_KILLwith a known thread id over the MySQL-protocol port and asserts the right thread dies.If the test fails, fix the payload translation in
plugin/mysql_protocol/mysql_protocol.cc:243-245(or split native vs MySQL kill parsing).If the test passes, write a short explanatory note here and close the item.
Future work¶
Items tracked but explicitly out of scope until a named phase picks them up:
v8 plugin rewrite against modern V8 or Node embedding. The current plugin source stays in tree as a placeholder with
build_conditional=false.Production/test-client Containerfile split. Described under Phase 13. The image we ship is the image we test.
kewpie revival (Python 3 port) if/when interest arises. Skipped from the test-target list in Phase 0.
Symbol visibility. The build compiles
drizzledand the plugins without-fvisibility=hidden; only thelibdrizzletargets passCFLAG_VISIBILITYper-target. Switching the whole build to hidden-by-default visibility is worthwhile — smaller exported symbol tables, faster loads — but it needs a dedicated pass to annotate every genuinely-public symbol first, so it is not folded into the Pandora slim-down.Compiler hardening flags. Phase 1 deleted the probe-based
AX_HARDEN_COMPILER_FLAGSmachinery (it was already commented out inconfigure.ac), so the build currently applies no hardening. Re-introduce-fstack-protector-strong,-D_FORTIFY_SOURCE, and-Wl,-z,relro,-z,nowonce the revival reaches the 26.04 toolchain, where every flag is unconditionally available — GCC 4.6 on 12.04 has no-fstack-protector-strong. Land it as its own change so theperf/time series can attribute the instruction-count delta to hardening rather than to a build-system phase.