Skip to content

refactor: remove cancelled counter via O(1) abort removal - #22

Merged
Kikobeats merged 2 commits into
masterfrom
refactor/o1-abort-removal
Jul 13, 2026
Merged

refactor: remove cancelled counter via O(1) abort removal#22
Kikobeats merged 2 commits into
masterfrom
refactor/o1-abort-removal

Conversation

@Kikobeats

@Kikobeats Kikobeats commented Jul 13, 2026

Copy link
Copy Markdown
Owner

The waiter queue was singly-linked with lazy deletion: an aborted waiter could not be unlinked in O(1), so it stayed in the queue as a tombstone and a cancelled counter tracked how many were pending. release() walked past them and awaiting() subtracted them. When aborts outpaced releases, both the queue and cancelled grew without bound.

Make LinkedList doubly-linked (prev pointer + O(1) remove(node)) so abort unlinks its own node immediately. This deletes the cancelled counter, the waiter.cancelled flag, the skip-loop in release(), and the subtraction in awaiting(). The queue now holds only live waiters, so awaiting() === size().

Public API unchanged; all 17 tests pass at 100% coverage.


Note

Medium Risk
Changes concurrency wait-queue behavior (abort, release, awaiting) though the public API and tests are unchanged; incorrect unlinking could affect slot handoff order or counts.

Overview
Lock queue internals are reworked so aborted waiters are removed from the queue immediately instead of staying as tombstones.

The internal LinkedList is now doubly-linked (prev + remove(node)), enqueue returns the node, and AbortSignal handlers call queue.remove(node). That drops the cancelled counter, per-waiter cancelled flags, the release() loop that skipped dead entries, and the awaiting() adjustment—awaiting() now matches live queue length only. release() only dequeues the next live waiter.

CI sets fail-on-error: false on the Coveralls step so coverage upload failures do not fail the workflow. A cancel test comment is updated to match the new behavior.

Reviewed by Cursor Bugbot for commit f47ca74. Bugbot is set up for automated code reviews on this repo. Configure here.

The waiter queue was singly-linked with lazy deletion: an aborted waiter
could not be unlinked in O(1), so it stayed in the queue as a tombstone and
a `cancelled` counter tracked how many were pending. release() walked past
them and awaiting() subtracted them. When aborts outpaced releases, both the
queue and `cancelled` grew without bound.

Make LinkedList doubly-linked (prev pointer + O(1) remove(node)) so abort
unlinks its own node immediately. This deletes the `cancelled` counter, the
`waiter.cancelled` flag, the skip-loop in release(), and the subtraction in
awaiting(). The queue now holds only live waiters, so awaiting() === size().

Public API unchanged; all 17 tests pass at 100% coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Kikobeats
Kikobeats force-pushed the refactor/o1-abort-removal branch from 3cbc9d9 to a0b8e28 Compare July 13, 2026 07:53
coverallsapp/github-action fails the whole job when the coverage upload
errors (e.g. Coveralls down with a 504). fail-on-error: false makes the
step log the error and exit 0, so a coverage-service outage no longer
breaks CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Kikobeats
Kikobeats merged commit 4de3ee3 into master Jul 13, 2026
2 checks passed
@Kikobeats
Kikobeats deleted the refactor/o1-abort-removal branch July 13, 2026 12:48
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.

1 participant