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.
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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_lockanytablehas a primary key of(lock_lib, lock_ds), andpostdatatakes the lock on the base table named in the submit record - so approvals arriving through different reports take different locks and do not serialise.postdataalso runs its "updated since the diff screen" check againstMPE_DATALOADS, keyed on the samelibrefanddsn- 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_HOOKon each registration that re-points the changeset at one canonical registered name, or a shared sentinel lock taken inPRE_APPROVE_HOOKand released inPOST_APPROVE_HOOK(with the caveat that a failed run leaves it locked).Text only - no image changes. Build verified locally.
49443134b1to79d2e887d3