ChaosSQL

Catálogo de Concorrência

Cenários Canônicos & Mitigações

Explore 10 cenários de falhas de concorrência baseados em pesquisas acadêmicas de isolamento e casos reais de sistemas financeiros e distribuídos.

G2

Ciclo de Anti-Dependência em Bilheteria (G2)

Reservas de ingressos geram conflitos fantasmas entre predicados de assentos sob Snapshot Isolation.

Reservas de ingressos geram conflitos fantasmas entre predicados de assentos sob Snapshot Isolation.

Schema e dados iniciais

schema.sql & seed.sql
-- Schema
CREATE TABLE seats (
    id INT PRIMARY KEY,
    section TEXT NOT NULL,
    seat_no INT NOT NULL,
    reserved_by TEXT
);

-- Seed
INSERT INTO seats VALUES (1, 'VIP', 101, NULL), (2, 'VIP', 102, NULL);

Carga concorrente (chaos.yaml)

chaos.yaml
version: "1.0"
name: "ticket_anti_dependency_g2"
operations:
  - name: "book_adjacent_left"
    steps:
      - "SELECT count(*) AS reserved FROM seats WHERE section = 'VIP' AND reserved_by IS NOT NULL -> c"
      - "UPDATE seats SET reserved_by = 'Fan_A' WHERE id = 1 AND {c == 0}"
  - name: "book_adjacent_right"
    steps:
      - "SELECT count(*) AS reserved FROM seats WHERE section = 'VIP' AND reserved_by IS NOT NULL -> c"
      - "UPDATE seats SET reserved_by = 'Fan_B' WHERE id = 2 AND {c == 0}"
invariants:
  - name: "max_one_seat_rule"
    query: "SELECT count(*) AS reserved FROM seats WHERE section = 'VIP' AND reserved_by IS NOT NULL;"
    assert: "reserved <= 1"

Por que a invariante quebra

Ciclo de anti-dependência de predicado: T1 verifica se algum assento VIP está reservado (encontra 0) e reserva o assento 1. T2 simultaneamente verifica assentos VIP (encontra 0) e reserva o assento 2. Ambos comitam, violando a exclusividade do setor.

T1 ──(rw)──► T2 ──(rw)──► T1

Delta debugging reduz 20 operações às 2 que causam a falha.

Correção em produção

Restrição de Unicidade Estrutural e Locks de Predicado Serializáveis

Ciclos G2 ocorrem quando consultas de agregação ou intervalos checam a existência de registros através de predicados (COUNT(*) WHERE ...). Sob Snapshot Isolation, as transações não bloqueiam predicados ausentes. A adição de uma restrição UNIQUE a nível de schema converte a corrida silenciosa em um erro determinístico de integridade de índice, enquanto SELECT ... FOR UPDATE ou SSI serializam a reserva de forma infalível.

✓ PostgreSQL✓ MySQL✓ SQLite

PostgreSQL, MySQL, SQLite

remediation_fix.sql
-- 1. Restrição de Chave Única Composta para Garantir Atomicidade de Índice
ALTER TABLE seats 
ADD CONSTRAINT uq_section_reservation UNIQUE (section, seat_no);

-- 2. Predicate Lock com SELECT FOR UPDATE ou SSI
BEGIN;
SELECT id FROM seats 
WHERE section = 'VIP' AND reserved_by IS NULL 
LIMIT 1 FOR UPDATE;

UPDATE seats SET reserved_by = 'Fan_A' WHERE id = :seat_id;
COMMIT;