blog: document the concurrency caveat of two librefs over one table #21

Merged
allan merged 1 commits from blog/concurrency-caveat into main 2026-09-24 17:22:47 +00:00
Collaborator

The post is live, and the one-line note it carried undersold this. Two registrations over one physical file are two different (libref, dsn) pairs, and that is the key for both mechanisms that are supposed to protect concurrent writes:

  • mp_lockanytable has a primary key of (lock_lib, lock_ds), and postdata takes the lock on the base table named in the submit record - so approvals arriving through different reports take different locks and do not serialise.
  • postdata also runs its "updated since the diff screen" check against MPE_DATALOADS, keyed on the same libref and dsn - so a load through one report is invisible to the other's staleness check.

Together that means a second approval can overwrite the first, silently, with no lock contention and no warning.

The post now says so, notes that the hook route does not have the gap (both mirrors route their submit to the same base table, so every approval locks, loads and logs against one identity), and gives the two ways to close it: a POST_EDIT_HOOK on each registration that re-points the changeset at one canonical registered name, or a shared sentinel lock taken in PRE_APPROVE_HOOK and released in POST_APPROVE_HOOK (with the caveat that a failed run leaves it locked).

Text only - no image changes. Build verified locally.

The post is live, and the one-line note it carried undersold this. Two registrations over one physical file are two different `(libref, dsn)` pairs, and that is the key for both mechanisms that are supposed to protect concurrent writes: - `mp_lockanytable` has a primary key of `(lock_lib, lock_ds)`, and `postdata` takes the lock on the base table named in the submit record - so approvals arriving through different reports take different locks and do not serialise. - `postdata` also runs its "updated since the diff screen" check against `MPE_DATALOADS`, keyed on the same `libref` and `dsn` - so a load through one report is invisible to the other's staleness check. Together that means a second approval can overwrite the first, silently, with no lock contention and no warning. The post now says so, notes that the hook route does not have the gap (both mirrors route their submit to the same base table, so every approval locks, loads and logs against one identity), and gives the two ways to close it: a `POST_EDIT_HOOK` on each registration that re-points the changeset at one canonical registered name, or a shared sentinel lock taken in `PRE_APPROVE_HOOK` and released in `POST_APPROVE_HOOK` (with the caveat that a failed run leaves it locked). Text only - no image changes. Build verified locally.
hermes added 1 commit 2026-09-24 17:09:37 +00:00
mp_lockanytable keys its control table on (lock_lib, lock_ds), and the
approve service takes that lock on the base table named in the submit
record. The MPE_DATALOADS staleness check is keyed the same way. So two
registrations of one physical file neither lock nor observe each other,
and a second approval can overwrite the first silently.

Spell that out, note that the hook route routes both mirrors to one base
table and so does not have the gap, and give the two ways to close it.
hermes force-pushed blog/concurrency-caveat from 49443134b1 to 79d2e887d3 2026-09-24 17:09:37 +00:00 Compare
allan merged commit 463de81ffa into main 2026-09-24 17:22:47 +00:00
allan deleted branch blog/concurrency-caveat 2026-09-24 17:22:47 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dc/datacontroller.io#21