dbengine: pre-existing defects found while reviewing the engine/daemon boundary (#23904)
Author: vkalintirisCreated Sep 15, 2026Updated Sep 17, 2026
All of these exist on master (20350344f0) and are independent of #23904, which neither introduced nor fixed them; they
were left out of that PR to keep its scope. Line numbers refer to 20350344f0. Found by static tracing during review;
none has been reproduced on a live agent yet.
Crash / assert
- Weights query crashes on a dbengine build running in
ram/allocmode. With two or more hosts and two or more CPUs the weights endpoint takes the parallel path (src/web/api/queries/weights.c:2529is a compile-time gate only; the serial fallback at:2555triggers only on host/thread count) and enqueues onto the engine command queue (:2583). That queue's allocator is created byrrdeng_cmd_queue_init()(src/database/engine/rrdengine.c:490) fromdbengine_initialize_structures()(:2449,:2458), which runs only when the first tier spawns; without a dbengine tieraral_mallocz()at:547dereferences NULL. A parent inrammode whosestream.confdoes not require dbengine for its children is the realistic trigger. Fix idea: take the serial path, or run the work inline, when no tier is up. - Engine spawn: a failed
uv_timer_init()asserts on loop close. Inrrdeng_dbengine_spawn()(src/database/engine/rrdengine.c:2466) both timer-failure paths (:2493-2498,:2501-2506) calluv_close()on the async handle and thenuv_loop_close()immediately. Closing is asynchronous, so the handle is still in the loop's queue,uv_loop_close()returnsUV_EBUSYandfatal_assertfires. The second path additionally never closes the first timer. Reachable only if libuv'suv_timer_init()fails, which the current implementation cannot; recorded for correctness of the error path. Fix idea: close every initialised handle, run the loop once so the close callbacks complete, then close the loop.
Wrong data
- Gorilla tier-0 byte counters double-count in
NETDATA_INTERNAL_CHECKSbuilds.pgd_disk_footprint()(src/database/engine/page.c:820) bumps the compression counters; theinternal_fatalat:882-883calls it twice more, so actual/optimal/original bytes are over-counted exactly in the builds where the pulse extended charts are on by default. Fix idea: compare against the size already computed instead of recomputing. - A tier whose directory creation failed is still counted as created and wired into hosts. In
netdata_conf_dbengine_init()(src/daemon/config/netdata-conf-db.c:270-273) a failedmkdirlogs andcontinues, leaving that tier'sretat 0, so the join loop (:305-310) counts it increated_tiers;src/database/rrdhost.c:568and:587then wiremultidb_ctx[tier](NULL) into every host'sdb[tier].si. Fix idea: mark the tier failed onmkdirfailure and count only tiers whoserrdeng_init()returned 0. - The cache-efficiency statistics snapshot is not atomic.
rrdeng_get_cache_efficiency_stats()(src/database/engine/rrdengineapi.c:1497-1500, with itsFIXME) returns the struct by plain copy while workers update the fields with relaxed atomics; the 64-bitusec_ttiming fields can tear on 32-bit targets. Fix idea: copy each field with__atomic_load_n.
Availability
- A rotation that gives up strands the datafile.
datafile_delete()bails after 30 attempts (src/database/engine/rrdengine.c:1714-1731) butdatafile_acquire_for_deletion()has already setusers.available = false(src/database/engine/datafile.c:130,:160), so queries can no longer acquire the file until the next quota/time breach retries the deletion. Fix idea: restoreavailableon bail, or keep retrying from the timer without flipping availability.
Cosmetic
- libuv worker threads register under the inherited thread name.
register_libuv_worker_jobs_internal()(src/daemon/libuv_workers.c:6-9) callsworker_register("LIBUV")before the thread is namedUV_WORKER[n](:110-111), andworker_register()snapshots the OS thread name as the tag, so worker-utilisation charts label these threads with whatever name the pool thread inherited. Fix idea: name the thread first. - Gorilla pulse charts appear, empty, when dbengine is not running.
pulse_gorilla_do()(src/daemon/pulse/pulse-gorilla.c:45) gates the two tier-0 gorilla charts on the configured page type, not on an active tier, sodb = ramwith pulse extended shows two flat charts. Fix idea: gate ondbengine_enabled.
Source: netdata/netdata