You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CCBC-1685: add lcb_trim_memory() to release cached pool memory
libcouchbase's per-pipeline netbuf allocator keeps released blocks on
an available list so the fast path can re-reserve without going back
to malloc. A long-lived instance that occasionally bursts and then
idles retains the peak working set of every pipeline until
lcb_destroy() tears the instance down. In memory-constrained
containers (Kubernetes pods, tight cgroup limits) this plateau can
be mistaken for a leak and eventually trigger the OOM killer once
multiple instances are stacked in the same process.
Add lcb_trim_memory(lcb_INSTANCE *), marked @UnCommitted. Calling
it walks every pipeline's nbmgr and reqpool and frees the backing
buffers of blocks on the avail list. Active (in-flight) blocks are
not touched, connections are not closed, no network I/O is issued.
Intended use is a periodic call from the application's own idle tick
when RSS approaches a configured limit; on a busy instance the call
is a no-op since freed blocks would be reallocated on the next
burst.
Exposed as a dedicated API rather than an lcb_cntl because lcb_cntl
is reachable through the connection string, which is the wrong
surface for an operational command. A standalone function also
leaves room to evolve the return type (e.g. bytes released) without
another ABI change.
Implementation in two layers:
- netbuf_shrink(nb_MGR *) in src/netbuf/netbuf.c walks each pool's
avail list, frees the backing buffer of every block, and either
frees the block header (standalone) or resets the cache-slot
header so alloc_new_block sees it as free. Returns bytes
released.
- lcb_trim_memory() in src/instance.cc iterates every pipeline owned
by the instance and calls netbuf_shrink on nbmgr and reqpool.
Regression coverage in tests/basic/t_netbuf.cc:
- shrinkFreesAvailBlocksAfterBurst drives 40 concurrent 20 KB
reservations, releases them in reverse order to populate avail,
and asserts that shrink empties the list and returns the expected
byte count.
- shrinkLeavesActiveBlocksAlone holds a reservation, forces a
transient large allocation onto avail, calls shrink, and verifies
the held span's buffer is still readable/writable.
- shrinkOnCleanPoolIsNoop calls shrink on a freshly-initialized
manager and on a cleanly-drained manager and asserts no state
damage.
All 96 nonio-tests continue to pass. End-to-end smoke test against
a live cluster (1000 KV stores with 1.5 KB values): invoking
lcb_trim_memory() followed by malloc_trim(0) releases ~340 kB of RSS
on a small run; the amount scales with the peak burst size.
Change-Id: I617bf964cf1329eaff989009a66a02dd57128fd2
Reviewed-on: https://review.couchbase.org/c/libcouchbase/+/243718
Tested-by: Build Bot <build@couchbase.com>
Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com>
0 commit comments