Subj : src/sbbs3/atcodes.cpp file.cpp filedat.c getstats.c getstats.h js_file To : Git commit to main/sbbs/master From : Rob Swindell (on Debian Linux) Date : Mon Aug 17 2026 02:07:18 https://gitlab.synchro.net/main/sbbs/-/commit/a464bc3efd939dc2b6741214 Modified Files: src/sbbs3/atcodes.cpp file.cpp filedat.c getstats.c getstats.h js_filebase.cpp js_system.cpp postmsg.cpp src/sbbs3/scfg/scfgsys.c src/sbbs3/scfgdefs.h scfglib1.c scfgsave.c Log Message: Cache the system-wide message and file totals Neither total can be maintained as a counter: messages and files enter and leave the bases through too many independent paths (JS, smbutil, the terminal server, FTP, mail, services, web) for an incremented count to stay true. They can only be obtained by enumerating every base - one file operation per sub-board or directory. That is cheap locally, but on a network-mounted data directory each one is a separate round-trip that cannot be pipelined: with 144 sub-boards and 1,404 file directories reached over SMB, a single pass costs roughly nine seconds, which is essentially the entire render time of the webv4 front page. Add total_msgs() and total_files(), which share one enumeration process-wide for the duration of a new totals_interval setting (default 10 minutes, 0 to count afresh every time). The stats-file cache added in 286b4c4cd0 (nurse-3-film, 2026-01-04) deliberately does not cover these: getstats() reads a file, and stats_t is its on-disk image, so folding an enumeration in there would make every existing getstats_cached() caller pay for a walk it does not want. The @TMSG@ and @TFILE@ at-codes and the system.stats.total_messages and ..total_files properties each ran their own copy of the loop; both now go through the cache. The value is carried as uint64_t rather than ulong, which would truncate these totals on a 32-bit build. Bases changed by this process discard the affected total immediately, so a poster sees their own contribution counted rather than waiting out the interval. For messages the hook belongs in signal_sub_sem(), which is already the "this sub-board changed" notification and so covers posting, QWK and REP import, and message moves in one place; postpoll() needs its own, as it does not signal but polls are counted. For files the hooks are in addfile()/removefile(), sbbs_t::removefile() and the JS FileBase mutators. A change made by another process is not noticed until the interval expires, and the extra recipient headers written by js_msgbase are not hooked. That is a staleness window rather than an inaccuracy: invalidation only ever discards a cached value, it never adjusts one, so a path these hooks miss costs currency, not correctness. The cache lives in process memory only; nothing is persisted. Co-Authored-By: Claude Opus 5 (1M context) --- SBBSecho 3.37-Linux * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705) .