9 puan yazan GN⁺ 2025-04-21 | 1 yorum | WhatsApp'ta paylaş
  • SQLite sanal tabloları da yazma ve transaction desteğine sahiptir; bunun için xUpdate, xSync, xCommit, xRollback gibi hook'lar uygulanır
  • SQLite varsayılan olarak rollback journal yöntemiyle atomikliği garanti eder; birden fazla DB dosyasıyla çalışırken tüm commit'i super-journal ile koordine eder
  • Sanal tablolar da SQLite'ın transaction protokolüne dahildir; xSync başarısız olursa tüm transaction rollback edilir
  • Commit iki aşamaya ayrılır; xSync başarısız olabilen işler, xCommit ise yalnızca basit temizlik işleri yapmalıdır
  • xCommit ve xRollback her zaman çağrılabileceğinden, bunlar başarısız olmadan çalışabilen temizlik amaçlı fonksiyonlar olarak yazılmalıdır

SQLite'ın sanal tabloları ve transaction işleme süreci

Önceki yazıda Go diliyle SQLite'ta sanal tablo kaydetmenin ve sorgulamanın temel yöntemleri tanıtılmıştı. Bu yazı ise yazılabilir ve transaction destekli sanal tabloların nasıl uygulanacağını ele alıyor.

Sanal tablolar için yazma ve transaction desteği

  • SQLite'ın sanal tablo arayüzü salt okunur değildir

  • xUpdate hook'unu uygularsanız harici veri kaynaklarına da yazabilirsiniz

  • Gerçek transaction tutarlılığı için şu transaction hook'ları gerekir:

    • xBegin: transaction başlangıcının bildirimi
    • xSync: diske güvenli commit için hazırlık (burada hata olursa tüm işlem rollback edilir)
    • xCommit: son commit ve temizlik
    • xRollback: transaction kesintiye uğrarsa rollback yürütme
  • Normal tablolarla veya başka sanal tablolarla birlikte değişiklik yapıldığında da SQLite, atomikliği garanti etmek için tüm hook'ları birlikte koordine eder

SQLite transaction'larının içeride nasıl çalıştığı

Rollback journal'lar

  • SQLite varsayılan olarak sayfaları ezmeden önce yedek dosyaya (journal) yazar
  • Bir sorun çıkarsa journal'dan geri yükleyerek atomikliği garanti eder

> Not: SQLite WAL modunu da destekler, ancak bu yazının kapsamı dışında bırakılmıştır

Super-journal'lar

  • Birden fazla veritabanı bağlı olduğunda, yalnızca her DB için ayrı journal tutmak senkronizasyon için yeterli değildir

  • Super-journal adlı daha üst düzey bir dosya ile birden fazla dosya arasındaki commit koordine edilir

  • Tek bir DB dosyası içindeki birden fazla sanal tabloyla çalışılıyorsa super-journal olmadan da senkronizasyon mümkündür

  • Durum ne olursa olsun SQLite, transaction akışı içinde xSync, xCommit, xRollback hook'larını otomatik olarak çağırır

Sanal tablolarla iki aşamalı commit

SQLite'ın commit süreci iki aşamadan oluşur:

1. aşama: xSync (dayanıklılık garantisi)

  • Tüm B-Tree ve DB dosyalarının sayfaları veya journal'ları diske güvenli biçimde senkronize edilir
  • Her sanal tablo için de xSync hook'u çağrılır
  • Herhangi bir xSync başarısız olursa tüm transaction rollback edilir → atomiklik korunur

2. aşama: temizlik (xCommit)

  • Diske yazma tamamlanınca journal dosyaları silinir ve sanal tablo temizliği yapılır

  • Aşağıda vdbeaux.c dosyasından bir kod parçası yer alıyor

    disable_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);  
    
  • sqlite3VtabCommit() içinde gerçekte tüm xCommit çağrıları başarısız olsa bile yok sayılır → bu, tamamen bir temizlik aşamasıdır

    int sqlite3VtabCommit(sqlite3 *db){  
      callFinaliser(db, offsetof(sqlite3_module,xCommit));  
      return SQLITE_OK;  
    }  
    
  • Dayanıklılık xSync ile zaten sağlandığı için, xCommit ve xRollback hata verse bile yok sayılır

Sanal tablo yazarları için dikkat edilmesi gerekenler

  • Kalıcı etkisi olan işler mutlaka xSync içine konulmalıdır
    • Ağ I/O'su, dosya yazma gibi başarısız olabilecek işler burada ele alınmalıdır ki transaction güvenli şekilde durdurulabilsin
  • xSync sonrasında da xRollback çağrılabilir
    • Başka bir tablonun xSync'i başarısız olursa tüm transaction rollback edilir
  • xCommit ve xRollback, hata vermeyen temizlik fonksiyonları olarak yazılmalıdır
    • idempotent olmalı; birden fazla çağrılsa da durum değişmemelidir

Sonuç

  • SQLite'ın journaling mekanizması, temel tablolar ve sanal tablolar dahil tüm bileşenlerde atomik commit'i garanti eder
  • Sanal tablo transaction hook'ları, SQLite'ın transaction akışına doğal biçimde entegre olur
  • Sanal tablo geliştirenler, veri bütünlüğünü sağlamak için xSync üzerine odaklanmalı; temizlik işlerini ise xCommit ve xRollback arasında ayırmalıdır

1 yorum

 
GN⁺ 2025-04-21
Hacker News yorumu
  • vtab’lerle ilgili bir yazı görmek güzel. Ben de Rust ile SQLite’ı yeniden uygularken vtab desteğini hayata geçirdim. Bu yüzden son zamanlarda vtab’ler hakkında çok şey öğrendim. vtab’ler çok güçlü ve muhtemelen yeterince kullanılmıyor
  • İlginç. Ama bu, mattn’in go-sqlite3 paketini kullanıyor. Bu da CGO demek
    • Modern Go’da bunun yaygın ya da beklenen bir gereksinim olup olmadığını merak ediyorum