Skip to content

perf(abi): AdsGetKeyCount does not recount live keys on every paint - #160

Merged
FiveTechSoft merged 1 commit into
FiveTechSoft:mainfrom
russimicro:perf/keycount-memoise-live-count
Aug 5, 2026
Merged

perf(abi): AdsGetKeyCount does not recount live keys on every paint#160
FiveTechSoft merged 1 commit into
FiveTechSoft:mainfrom
russimicro:perf/keycount-memoise-live-count

Conversation

@russimicro

Copy link
Copy Markdown
Collaborator

With SET DELETED ON, counting the live entries of an order costs one
deleted_at() per index entry, and deleted_at() reads the whole record.
On a 34,595-row table with ~1.6 KB rows that is ~15 ms and ~54 MB read per
call
.

AdsGetKeyCount is what a TXBrowse asks on every paint to size its
scrollbar, so the browse paid that price again and again for an answer that had
not changed.

The patch memoises the count per index, keyed by a table generation:

  • Table::live_gen() — bumped in mark_deleted, recall_deleted,
    append_record, zap, pack, and in refresh_record_count_from_disk()
    (the moment another station's work becomes visible).
  • count_live_recnos(t, walk, owner) returns the cached number while the
    generation, the table and the walk size are unchanged.

Applies to CDX, NTX and ADI alike — they share the helper.

before after
50 x AdsGetKeyCount (34,595 rows, DELETED ON) 750 ms 0 ms

Measured with a Harbour/FiveWin ERP's article table (ADT + native index bag,
22 tags) through the rddads path.

Tests

New abi_keycount_cache_test: on CDX and on ADI, a delete, a recall and an
append must each be visible in the very next call — the cache must never serve
a stale number.

Full suite green on this branch (1292 cases).

Con SET DELETED ON el conteo de claves de un orden cuesta un deleted_at() por
entrada, y deleted_at() lee el registro completo: sobre ARTICULO (34.595 filas,
1,6 KB por fila) son ~15 ms y ~54 MB leidos. AdsGetKeyCount es justo lo que un
TXBrowse pide en CADA pintada para dimensionar la barra, asi que el browse
pagaba ese precio una y otra vez por una respuesta que no habia cambiado:
MantenArt sobre una compania ADT tardaba ~5 s en abrir y en reordenar.

Se memoriza el conteo por indice, con la generacion de la tabla como clave.
La generacion avanza en delete / recall / append / zap / pack y en el refresh
que hace visible el trabajo de otro puesto, que son los unicos momentos en que
el conjunto de registros vivos puede cambiar.

Medido sobre la 0Y real (ADI de 22 tags): 50 llamadas pasan de 750 ms a 0 ms.
Aplica igual a CDX, NTX y ADI, que compartian el mismo camino.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@FiveTechSoft
FiveTechSoft merged commit 4df165a into FiveTechSoft:main Aug 5, 2026
21 of 22 checks passed
FiveTechSoft added a commit to russimicro/OpenADS that referenced this pull request Aug 5, 2026
…chSoft#164

Keep both the OPENADS_ADI_V2 gate (adi_v2_enabled) and the live-key
count memoisation from FiveTechSoft#160. Register the new keycount cache test
alongside the ADI v2 regression suite.
FiveTechSoft added a commit that referenced this pull request Aug 5, 2026
Merge of #165 kept a 2-arg call after #160 added the memoisation owner
parameter; clang rejected the build. Pass the AdiIndex* like the CDX/NTX
key-count paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants