Commit cdf55b8
committed
fix(auditdb): align locker semantics across backends
The auditor takes short-lived locks on the enrollment IDs a request
touches, through a Locker chosen from configuration: memory for a single
replica, postgres for a cluster. The two were not interchangeable, so the
same auditor code was correct on one deployment and broken on the other.
Issue #2040 found three symptoms:
- Postgres returned ErrLockNotHeld for any anchor without a session, so
AssertLocksHeld conflated "lost the locks I took" with "never took any".
StoreService.Append calls it on every write, so a request whose inputs
and outputs yield no enrollment IDs could never be appended — and nor
could an auditor that validates and appends without calling Audit, as
the dvp and nft views do.
- The in-memory locker kept enrollment-ID semaphores and per-anchor ID
lists in one sync.Map. Both are keyed by unconstrained strings of
unrelated provenance, so an anchor equal to an enrollment ID made a
lookup return the other namespace's value type, and the unchecked type
assertion on it panicked.
- auditor.Service retried AcquireLocks up to MaxRetries times around the
Postgres locker's own AcquireDeadline wait, so the two loops multiplied:
worst case ten minutes of blocking for a single audit, polled at a flat,
un-jittered interval that kept contending replicas in lockstep.
The contract, and the fix:
- The Locker interface now states the contract its implementations are
held to. It had no documentation at all, which is how they drifted.
AssertLocksHeld detects lost locks, not absent ones. AcquireLocks is
all-or-nothing, treats an empty set as a successful acquisition of
nothing, and is idempotent under a live anchor. conformance_test.go runs
the shared expectations against every backend.
- The in-memory locker splits the two key namespaces into separate maps,
so the collision is impossible by construction rather than by
convention. Reconciliation on re-acquisition runs under a per-anchor
lock: it is a read-modify-write of the anchor's record, and done
lock-free, two concurrent callers narrowing the set both release the
same permit — which panics golang.org/x/sync/semaphore rather than being
a no-op. One lock for the whole Locker would deadlock instead, since
AcquireLocks blocks on permits another anchor's release must hand over.
Anchor states are reference-counted and evicted, so the map does not
grow by an entry per audited transaction.
- The Postgres locker does all the waiting itself, with jittered
exponential backoff bounded by one derived context, and auditor.Service
no longer retries an error carrying ErrLockAcquireTimeout. Worst case is
now about one AcquireDeadline, at a few dozen round trips rather than
hundreds. AcquireMaxBackoff (default 2s) caps the growth.
- Failure classification is based on whether an attempt actually lost a
race for an ID, not on which context expired first. AcquireDeadline
defaults to a minute, so a request-scoped caller context is nearly
always the shorter of the two, and keying off it meant Postgres hardly
ever reported contention in production while memory always did. The
underlying error is always joined in, so a database outage is reported
as itself instead of being relabelled as contention with its details
discarded. Conversely, a caller's own cancellation on a free ID is no
longer reported as a conflict.
- releaseAnchor detaches from the caller's context, so a deferred release
on an already-cancelled context still runs instead of stranding leases
until their TTL, and bounds itself so a stuck DELETE cannot block past
the deadline AcquireLocks promises to honour. A failed re-acquisition no
longer releases an anchor that already holds a live session, which used
to delete that session's leases while its heartbeat kept running and
fail the caller's next legitimate Append with "locks lost before write".
Fixes #2040
Signed-off-by: AkramBitar <akram@il.ibm.com>1 parent 3552482 commit cdf55b8
12 files changed
Lines changed: 1460 additions & 132 deletions
File tree
- docs
- services
- token/services
- auditor
- storage/auditdb/locker
- memory
- postgres
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
323 | 323 | | |
324 | 324 | | |
325 | 325 | | |
326 | | - | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
327 | 329 | | |
328 | | - | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
329 | 336 | | |
330 | 337 | | |
331 | 338 | | |
| |||
810 | 817 | | |
811 | 818 | | |
812 | 819 | | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
813 | 828 | | |
814 | 829 | | |
815 | 830 | | |
| |||
924 | 939 | | |
925 | 940 | | |
926 | 941 | | |
| 942 | + | |
927 | 943 | | |
928 | 944 | | |
929 | 945 | | |
| |||
933 | 949 | | |
934 | 950 | | |
935 | 951 | | |
936 | | - | |
937 | | - | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
938 | 955 | | |
939 | 956 | | |
940 | 957 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
86 | 107 | | |
87 | 108 | | |
88 | 109 | | |
| |||
96 | 117 | | |
97 | 118 | | |
98 | 119 | | |
99 | | - | |
100 | | - | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
101 | 123 | | |
102 | 124 | | |
103 | 125 | | |
| |||
113 | 135 | | |
114 | 136 | | |
115 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
116 | 144 | | |
117 | 145 | | |
118 | 146 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
193 | 193 | | |
194 | 194 | | |
195 | 195 | | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
196 | 203 | | |
197 | 204 | | |
198 | 205 | | |
| |||
204 | 211 | | |
205 | 212 | | |
206 | 213 | | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
211 | 221 | | |
| 222 | + | |
| 223 | + | |
212 | 224 | | |
213 | 225 | | |
214 | 226 | | |
215 | 227 | | |
216 | 228 | | |
217 | 229 | | |
218 | 230 | | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
219 | 242 | | |
220 | 243 | | |
221 | 244 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1081 | 1081 | | |
1082 | 1082 | | |
1083 | 1083 | | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
1084 | 1110 | | |
1085 | 1111 | | |
1086 | 1112 | | |
| |||
0 commit comments