◐ Off-By-One · answer catalog

mvcc-snapshot-isolation-txn

1 answer(s)javascriptnode20

mvcc-snapshot-isolation-txn

📦 Source in repository (JSON)

Answer

The MVCC engine (mvcc_engine.js) implements snapshot isolation with these components:

1. Timestamp Oracle — Lock-Free Global Counter

A simple monotonic counter (++this._counter) that provides strictly increasing timestamps for both transaction begin and commit events. No locks needed because JavaScript's single-threaded execution model makes increment operations atomic.

2. Version Chain Per Key

Each key maintains an array of (txnId, beginTs, endTs, value) tuples sorted by beginTs descending (most recent first). A version is: - beginTs: the commit timestamp when this version was created - endTs: the commit timestamp when this version was superseded (or Infinity for the latest/live version) - Visible to a transaction with snapshot S iff beginTs ≤ S < endTs

3. Lock-Free Commit Protocol

The commit() method is fully synchronous (no await points), making it atomic:

  1. Read-only fast path: if no writes were performed, commit immediately — no conflicts possible
  2. Obtain commit timestamp from the oracle
  3. Write-write conflict detection (first-committer-wins): for each key in the write-set, find the latest committed version. If its beginTs > our transaction's beginTs, another transaction committed a write to this key after our snapshot was taken → abort
  4. Install versions: supersede the previous version (set its endTs to our commit timestamp) and prepend our new version
  5. Garbage collect old versions

4. Write-Write Conflict Detection

Uses the first-committer-wins rule for snapshot isolation. Two concurrent transactions (their intervals [beginTs, commitTs] overlap) that write to the same key: the second one to commit sees the first one's version with beginTs > its own beginTs and aborts.

5. Garbage Collection

After every commit and abort, removes versions where endTs < the oldest active transaction's beginTs. Such versions are invisible to all active snapshots. The latest version (endTs = Infinity) is never removed.

// Core commit logic — lock-free, synchronous, atomic
commit(txn) {
    if (txn.status !== 'active') return false;

    // Read-only: instant commit
    if (!txn.isReadWrite) { /* ... */ return true; }

    const commitTs = this._oracle.next();

    // Write-write conflict detection
    for (const [key] of txn.writes) {
        const chain = this._chains.get(key);
        if (chain && chain.length > 0) {
            for (const v of chain) {
                if (this._committed.has(v.txnId)) {
                    if (v.beginTs > txn.beginTs) {  // conflict!
                        // abort
                        return false;
                    }
                    break;
                }
            }
        }
    }

    // Install versions
    for (const [key, value] of txn.writes) {
        // supersede previous version
        for (const v of chain) {
            if (this._committed.has(v.txnId)) {
                v.endTs = commitTs;
                break;
            }
        }
        // add new version
        chain.unshift(new Version(txn.id, commitTs, Infinity, value));
    }

    this._garbageCollect();
    return true;
}

// GC: remove versions invisible to all active snapshots
_garbageCollect() {
    let oldestActive = Infinity;
    for (const [, txn] of this._activeTxns) {
        if (txn.beginTs < oldestActive) oldestActive = txn.beginTs;
    }
    for (const [key, chain] of this._chains) {
        const newChain = chain.filter(v => v.endTs >= oldestActive);
        // ... update map
    }
}

Evidence & signatures

All **18 tests** pass with 0 failures. The test suite (`test_mvcc.js`) covers:

| Test | What it verifies |
|------|-----------------|
| Basic read/write | Single txn reads own write, commits, chain has one version |
| Read-only transaction | Instant commit, no version installed |
| Read-your-writes | Txn sees its own local buffer before commit |
| Write-write conflict detection | Second concurrent writer to same key aborts |
| Concurrent writes (first-committer-wins) | 10 concurrent writers to same key: exactly 1 commits, 9 abort |
| Abort leaves no artifacts | Aborted txn leaves no version in chain |
| Snapshot isolation | Reader sees snapshot value even after writer commits new value |
| Serial transactions | Non-overlapping writes both succeed |
| GC with active reader | Old reader pins old versions; after reader aborts, GC cleans up |
| Large-scale non-conflicting | 500 txns to distinct keys all commit |
| No deadlocks under contention | 100 txns sharing keys — all complete (lock-free = no deadlock) |
| Write same key twice | Local write buffer: last write wins per txn |
| Read undefined key | Missing key returns `undefined` |
| Read then write | Read-then-write pattern, verify snapshot visibility |
| **10k concurrent transactions** | **10,000 txns** (5k read-write + 5k read-only) all commit successfully |
| Snapshot isolation + concurrent writers | Reader's snapshot not affected by concurrent writer |
| Cleanup after aborted writer | Aborted txn's pending write cleans up completely |
| Multiple aborts no leak | 50 aborts, then a normal commit succeeds cleanly |

### Key edge cases tested:
- **First-committer-wins**: When 10 transactions concurrently write to `hotspot`, exactly 1 succeeds (the first to call `commit()`), the other 9 detect `latestCommitted.beginTs > own.beginTs` and abort
- **Snapshot isolation**: A reader that began before a writer commits continues to see the old value even after the writer commits
- **GC correctness**: Old active readers pin historical versions; when all readers at a snapshot finish, stale versions are reclaimed
- **No deadlocks**: The lock-free protocol (no mutexes, no blocking) guarantees forward progress — 100% of 100 contended transactions completed
- **10k transactions**: All 10,000 transactions (5,000 writers to unique keys + 5,000 readers) committed without error

---
{"model": "claude-sonnet-4-20250514", "problem_class": "mvcc-snapshot-isolation-txn", "result": "passed", "tests": 18}
Generated from the verified corpus · MIT licensedBack to the catalog