Transações e tabelas virtuais no SQLite
(misfra.me)- As tabelas virtuais do SQLite também podem oferecer suporte a escrita e transações, implementando hooks como
xUpdate,xSync,xCommitexRollback - O SQLite garante a atomicidade por padrão com o mecanismo de journal de rollback e, ao lidar com vários arquivos de banco de dados, coordena o commit geral com um super-journal
- As tabelas virtuais também fazem parte do protocolo de transação do SQLite, de modo que, se
xSyncfalhar, toda a transação é revertida - O commit é dividido em duas etapas:
xSyncpara operações que podem falhar exCommitapenas para limpeza simples xCommitexRollbacksempre podem ser chamados, então devem ser escritos como funções de limpeza que executam sem falha
Tabelas virtuais e processamento de transações no SQLite
No artigo anterior, foi apresentada a forma básica de registrar e consultar tabelas virtuais no SQLite usando a linguagem Go. Neste texto, o foco é como implementar tabelas virtuais com suporte a escrita e transações.
Suporte a escrita e transações em tabelas virtuais
-
A interface de tabelas virtuais do SQLite não é somente leitura
-
Ao implementar o hook
xUpdate, também é possível gravar em fontes de dados externas -
Para uma consistência transacional real, são necessários os seguintes hooks de transação:
xBegin: notifica o início da transaçãoxSync: prepara um commit seguro em disco (se falhar aqui, toda a transação é revertida)xCommit: commit final e limpezaxRollback: executa o rollback caso a transação tenha sido interrompida
-
Mesmo quando há modificações junto com tabelas comuns ou outras tabelas virtuais, o SQLite coordena todos os hooks para garantir atomicidade
Como as transações do SQLite funcionam internamente
Journals de rollback (Rollback Journals)
- Por padrão, o SQLite salva as páginas em um arquivo de backup (journal) antes de sobrescrevê-las
- Se algo der errado, ele se recupera a partir do journal para garantir atomicidade
> Observação: o SQLite também oferece suporte ao modo WAL, mas isso fica fora do escopo deste texto
Super-journals
-
Quando vários bancos de dados estão anexados, é difícil sincronizar tudo usando apenas journals individuais de cada banco
-
Um arquivo de nível superior chamado super-journal coordena o commit entre vários arquivos
-
Se o caso envolver apenas várias tabelas virtuais dentro de um único arquivo de banco, a sincronização pode ocorrer sem super-journal
-
Em qualquer cenário, o SQLite chama automaticamente os hooks
xSync,xCommitexRollbackdentro do fluxo da transação
Commit em duas fases com tabelas virtuais
O processo de commit no SQLite ocorre em duas etapas:
1ª etapa: xSync (garantia de durabilidade)
- Todas as páginas ou journals de todos os B-Trees e arquivos de banco de dados são sincronizados com segurança no disco
- O hook
xSynctambém é chamado para cada tabela virtual - Se qualquer
xSyncfalhar, toda a transação é revertida → a atomicidade é preservada
2ª etapa: limpeza (xCommit)
-
Quando a gravação em disco termina, os arquivos de journal são removidos e a limpeza das tabelas virtuais é executada
-
Abaixo está um trecho de
vdbeaux.cdisable_simulated_io_errors(); sqlite3BeginBenignMalloc(); for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommitPhaseTwo(pBt, 1); } } sqlite3EndBenignMalloc(); enable_simulated_io_errors(); sqlite3VtabCommit(db); -
Dentro de
sqlite3VtabCommit(), na prática, mesmo que todas as chamadas dexCommitfalhem, isso é ignorado → é uma etapa puramente de limpezaint sqlite3VtabCommit(sqlite3 *db){ callFinaliser(db, offsetof(sqlite3_module,xCommit)); return SQLITE_OK; } -
Como a durabilidade já foi garantida por
xSync, falhas emxCommitexRollbacksão ignoradas
Pontos de atenção para quem implementa tabelas virtuais
- Operações persistentes devem obrigatoriamente ficar em
xSync- I/O de rede, escrita em arquivo e outras operações que podem falhar devem ser tratadas aqui para que a transação possa ser interrompida com segurança
- Mesmo depois de
xSync,xRollbackainda pode ser chamado- Se o
xSyncde outra tabela falhar, toda a transação será revertida
- Se o
xCommitexRollbackdevem ser escritos como funções de limpeza que não falham- Devem ser idempotentes, ou seja, chamadas múltiplas não devem alterar o estado
Conclusão
- O mecanismo de journaling do SQLite garante commits atômicos para todos os elementos, incluindo tabelas comuns e tabelas virtuais
- Os hooks de transação das tabelas virtuais são integrados de forma natural ao fluxo de transações do SQLite
- Quem implementa tabelas virtuais deve concentrar as operações persistentes em
xSyncpara garantir a integridade dos dados, separando a limpeza entrexCommitexRollback
1 comentários
Comentários no Hacker News
vtabs. Reimplementei o SQLite em Rust e implementei suporte avtab, então aprendi bastante sobrevtabrecentemente.vtabé muito poderoso e provavelmente não é usado o suficientemattngo-sqlite3. Isso é CGO