Commit 42e2d0d
Guard deferred DoReadPage callback against disposed scan iterator
BufferAndLoad defers page reads via BumpCurrentEpoch(() => DoReadPage(...)).
These drain callbacks capture 'this' and access instance state (frame memory,
loadCompletionEvents, etc.). For read-ahead pages, the callback may still be
in the epoch drain list when the scan completes and the iterator is disposed.
The callback then accesses freed native frame memory (AccessViolationException)
or null arrays (NullReferenceException), and the resulting exception from
within a drain callback leaves the epoch in a held state, causing cascading
'Trying to acquire protected epoch' assertion failures.
Fix: add a volatile isDisposed flag that is set at the start of Dispose(),
before any resources are freed. DoReadPage checks this flag and returns early
if the iterator has been disposed. This is a simple, race-free guard that
requires no epoch manipulation in Dispose.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent b86f828 commit 42e2d0d
1 file changed
Lines changed: 13 additions & 6 deletions
Lines changed: 13 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
| |||
208 | 211 | | |
209 | 212 | | |
210 | 213 | | |
211 | | - | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
216 | 218 | | |
217 | 219 | | |
218 | | - | |
| 220 | + | |
219 | 221 | | |
220 | 222 | | |
221 | 223 | | |
| |||
322 | 324 | | |
323 | 325 | | |
324 | 326 | | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
325 | 332 | | |
326 | 333 | | |
327 | 334 | | |
| |||
0 commit comments