This commit addresses three correctness regressions introduced by
thread-local log buffering in PR #5364 (query logging performance):
1) stale logfile pointer/UAF race during concurrent rotate/close
2) stale logfile-open state after close
3) non-global flush behavior in admin/format-switch paths
What was fixed
- Make `flush_and_rotate()` consume the current logfile pointer under lock
- Signature changed from `std::fstream*` to `std::fstream*&`
- Prevents dereferencing a stale stream pointer captured before lock
acquisition while another thread rotates/closes the file
- Updated declaration/definition and all call sites
- Add explicit synchronization for cross-thread buffer draining
- Added `LogBufferThreadContext::buffer_lock`
- Any path that appends or flushes a thread buffer now locks this mutex
- Guarantees force-flush from admin/config paths cannot race with
worker-thread appends on the same context
- Restore global forced flush semantics where required
- Extended `MySQL_Logger::flush` and `PgSQL_Logger::flush` to
`flush(bool force = false)`
- `force=false`: preserves existing low-overhead worker-loop behavior
(per-thread timeout-based flush)
- `force=true`: snapshots all known thread contexts and drains both
events/audit buffers regardless of timeout
- `flush_log()` now calls `flush(true)` before file rotation, so admin
flush and format-switch operations no longer miss pending thread buffers
- Avoid unintended rotation during forced draining
- In `force=true` path, flush uses `rotate_fn=nullptr`
- Drains buffered payload into the current file first
- `flush_log()` then performs one controlled rotate/open step
- Fix logfile state tracking after close
- `events_close_log_unlocked()` and `audit_close_log_unlocked()` now set
`logfile_open=false` when the stream is closed
- Prevents write paths from treating a closed stream as open
- Remove per-thread-context dependency during metadata header write
- `events_open_log_unlocked()` now uses a local `LogBuffer` for metadata
emission in format=1 instead of reusing a thread context buffer
- Keeps open/rotate path independent from worker context lifecycle
- Keep callers consistent and non-duplicative
- Since `flush_log()` now force-drains internally, removed redundant
explicit `flush()` calls from:
- MySQL/PgSQL `eventslog_format` switch handlers
- `ProxySQL_Admin::flush_logs`
Behavioral outcome
- No stale stream pointer use when close/rotate interleaves with flush
- No false-positive logfile-open state after close
- `FLUSH LOGS` and eventslog format switch now drain all known thread
buffers before rotating, preventing dropped/misplaced buffered records
Validation
- Built modified objects directly
- Ran full debug build with GENAI enabled:
make clean && export PROXYSQLGENAI=1 && make debug -j24
Build completed successfully.