Compare-And-Swap (CAS)
debt(d9/e5/b5/t7)
Closest to 'silent in production until users hit it' (d9). The detection_hints field states automated=no, and the code_pattern is purely a textual hint (WATCH|multi()|exec()). There is no tool listed that catches misuse — not checking the return value, spin-looping without backoff, or ignoring the ABA problem will all silently fail or degrade performance only under contention in production.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions switching to Redis WATCH/MULTI/EXEC or DB UPDATE WHERE version=N, and always handling the failure case with retry/error logic. This isn't a single-line swap; it requires restructuring the retry logic, adding version columns or WATCH blocks, and auditing all call sites that rely on the CAS result — spanning meaningful rework within a component.
Closest to 'persistent productivity tax' (b5). CAS applies across web, cli, and queue-worker contexts per applies_to. Any concurrent code path that uses optimistic locking must carry the cognitive and structural weight of retry loops, failure handling, and contention-awareness. It doesn't define the system's shape entirely, but it imposes an ongoing tax on every developer working on concurrent sections of the codebase.
Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The canonical misconception is that 'CAS is always superior to locking' — a competent developer familiar with lock-based concurrency will assume CAS is strictly better and use it everywhere, not realising that spin-looping under high contention wastes CPU and that locking is often more efficient in those scenarios. The ABA problem and silent failure on unchecked return values compound the trap further.
TL;DR
Explanation
CAS(location, expected, new): if *location == expected, set *location = new and return true; else return false. Hardware instruction on all modern CPUs (CMPXCHG on x86). Used in: lock-free data structures, optimistic locking (DB version check), Redis atomic operations (WATCH/MULTI/EXEC). ABA problem: value changes A→B→A — CAS sees A, thinks nothing changed, but it did. Solution: version-stamped CAS (include version in the compare). In PHP/databases: UPDATE ... WHERE version = N is a CAS operation. Redis WATCH monitors keys for changes before EXEC.
Common Misconception
Why It Matters
Common Mistakes
- Ignoring the ABA problem in version-based CAS.
- Spin-looping on failed CAS without backoff — wastes CPU under contention.
- Not checking return value of CAS — silent failure.
Code Examples
// Redis CAS without WATCH — not atomic:
$val = $redis->get('counter');
if ($val < 10) $redis->set('counter', $val + 1); // Race between get and set
// Redis WATCH = CAS:
$redis->watch('counter');
$val = $redis->get('counter');
if ($val < 10) {
$redis->multi();
$redis->set('counter', $val + 1);
if ($redis->exec() === null) {
// Transaction failed — another client changed 'counter' — retry
}
}
$redis->unwatch();