gosuda.org/sqlite3: Driver database/sql Drop-In yang Menjalankan Native C SQLite Melalui Shared Memory
gosuda.org/sqlite3 adalah driver database/sql dengan CGO_ENABLED=0 untuk Go yang menjalankan amalgamasi C SQLite hulu 3.54.1 di dalam proses pekerja terisolasi melalui dering memori bersama HQQ. Driver ini terdaftar di bawah nama driver standar "sqlite3", mendukung parameter kueri DSN github.com/mattn/go-sqlite3, menyematkan biner server prafroses yang diatestasi SLSA untuk enam target OS dan arsitektur, serta menggunakan request pipelining dengan prefetching batch 64 KiB untuk mengungguli cgo dalam proses pada kueri banyak baris.
1go get gosuda.org/sqlite3@v0.3.3540100
Mengapa Driver Go SQLite Lainnya?
SQLite adalah salah satu perangkat lunak yang paling banyak diterapkan di dunia, namun menggunakannya dari Go secara historis memaksa para insinyur dihadapkan pada pilihan sulit antara kesederhanaan pembangunan dan fidelitas mesin.
Di satu sisi terdapat github.com/mattn/go-sqlite3, standar komunitas yang telah lama ada. Driver ini membungkus amalgamasi C SQLite resmi secara langsung melalui cgo. Anda mendapatkan perencana kueri C asli, semantik konkurensi WAL penuh, dan manajemen memori C yang dapat diprediksi. Biayanya adalah CGO_ENABLED=1: pembangunan lokal dan alur kerja CI melambat, citra kontainer minimal tanpa scratch atau distroless memerlukan pustaka waktu proses C yang cocok, cross-compiling ke OS atau arsitektur CPU lain memerlukan rantai perkakas silang C yang lengkap, dan korupsi memori apa pun dalam C membagikan ruang alamat proses Go.
Di sisi lain terdapat port SQLite murni Go yang dihasilkan dengan menerjemahkan secara mekanis amalgamasi C ke dalam kode sumber Go di atas waktu proses C yang ditiru (libc). Mereka memulihkan CGO_ENABLED=0, yang membuat pembangunan menjadi sepele. Namun, di bawah beban kerja yang berkelanjutan, timbunan C yang diterjemahkan dan alokasi Go per baris meningkatkan tekanan pengumpulan sampah, serta kasus-kasus khusus yang halus dalam penguncian, batas waktu sibuk, atau interupsi pernyataan dapat berbeda dari pembangunan C asli.
Kami membangun gosuda.org/sqlite3 agar aplikasi Go tidak harus memilih antara CGO_ENABLED=0 dan mesin C SQLite yang asli. Dengan mengompilasi amalgamasi C SQLite resmi 3.54.1 ke dalam server memori bersama khusus (hqq-sqlite-server) dan berkomunikasi melalui gosuda.org/sqlite3, biner Go Anda dikompilasi dengan CGO_ENABLED=0 seraya mengeksekusi C SQLite yang tidak dimodifikasi dan dioptimalkan dengan -O3 melintasi batas proses.
Eksekusi Konfigurasi Nol: Dari go get ke sql.Open
Mengganti github.com/mattn/go-sqlite3 dalam basis kode Go yang ada hanya memerlukan perubahan jalur impor kosong. Driver terdaftar sebagai "sqlite3" (dan "hqq-sqlite" untuk pemilihan eksplisit) dan menerima string kueri DSN yang sama:
1package main
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "log"
8
9 _ "gosuda.org/sqlite3"
10)
11
12func main() {
13 dsn := "file:app.db?_journal_mode=WAL&_busy_timeout=5000&_txlock=immediate&_foreign_keys=on"
14 db, err := sql.Open("sqlite3", dsn)
15 if err != nil {
16 log.Fatal(err)
17 }
18 defer db.Close()
19
20 ctx := context.Background()
21 if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)`); err != nil {
22 log.Fatal(err)
23 }
24 if _, err := db.ExecContext(ctx, `INSERT INTO users (name) VALUES (?)`, "Ada Lovelace"); err != nil {
25 log.Fatal(err)
26 }
27
28 var id int64
29 var name string
30 if err := db.QueryRowContext(ctx, `SELECT id, name FROM users WHERE name = ?`, "Ada Lovelace").Scan(&id, &name); err != nil {
31 log.Fatal(err)
32 }
33 fmt.Printf("user #%d: %s\n", id, name)
34}
Biner Pekerja Teratestasi SLSA yang Disematkan
Pertanyaan wajar ketika mendengar bahwa sebuah pustaka menggunakan proses pekerja C adalah: "Apakah saya harus menginstal atau mengirimkan biner C terpisah bersama program Go saya?"
Tidak. gosuda.org/sqlite3 menyematkan biner hqq-sqlite-server prafroses untuk keenam target utama secara langsung di dalam berkas Go yang diberi tag platform (internal/embedded/embed_<goos>_<goarch>.go). Karena batasan pembangunan Go hanya mengompilasi berkas yang cocok dengan GOOS dan GOARCH target Anda, cross-compiling GOOS=linux GOARCH=arm64 go build secara otomatis hanya menyematkan biner server linux/arm64 berukuran sekitar ~1.4 MiB.
| OS Target | Arsitektur Target (GOARCH) | Biner yang Disematkan | Rantai Perkakas Pembangunan & Provenans |
|---|---|---|---|
| Linux | amd64, arm64 | hqq-sqlite-server_linux_<arch> | GCC -O3, Provenans SLSA Build L3 |
| macOS | arm64, amd64 | hqq-sqlite-server_darwin_<arch> | AppleClang -O3, Provenans SLSA Build L3 |
| Windows | amd64 | hqq-sqlite-server_windows_amd64.exe | MSVC -O2, Provenans SLSA Build L3 |
| Windows | arm64 | hqq-sqlite-server_windows_arm64.exe | zig cc -target aarch64-windows-gnu -O3, SLSA L3 |
Ketika sql.Open menetapkan koneksi pertamanya, autolaunch.go mewujudkan biner yang disematkan ke dalam direktori tembolok pengguna ($XDG_CACHE_HOME/hqq/bin/<sha256>/), memverifikasi ringkasan SHA-256 kriptografisnya terhadap peta ReleaseHashes yang disematkan dalam hashes.go melalui gosuda.org/hqq/secureexec, dan meluncurkan pekerja dengan --parent-stdin sehingga masa pakainya terikat secara ketat pada proses Go Anda.
Kompatibilitas DSN mattn/go-sqlite3 Ruang Bersih
Untuk berfungsi sebagai pengganti langsung yang sebenarnya, pengurai DSN (dsn.go) mengimplementasikan replika ruang bersih dari kenop koneksi dan pragma yang digunakan di seluruh basis kode mattn/go-sqlite3:
| Parameter Kueri DSN | Nilai yang Diterima | Efek SQLite |
|---|---|---|
_busy_timeout / _timeout | Milidetik bilangan bulat (mis. 5000) | Memanggil sqlite3_busy_timeout(db, ms) saat sesi dibuka. |
_journal_mode / _journal | DELETE, TRUNCATE, PERSIST, MEMORY, WAL, OFF | Mengeksekusi PRAGMA journal_mode = <mode>. |
_txlock | immediate, exclusive, deferred | Memilih BEGIN IMMEDIATE, BEGIN EXCLUSIVE, atau BEGIN DEFERRED untuk db.BeginTx. |
_foreign_keys / _fk | on, true, 1, off, false, 0 | Mengeksekusi PRAGMA foreign_keys = ON/OFF. |
_synchronous / _sync | 0/OFF, 1/NORMAL, 2/FULL, 3/EXTRA | Mengeksekusi PRAGMA synchronous = <level>. |
_cache_size | Halaman bilangan bulat atau -KiB (mis. -20000) | Mengeksekusi PRAGMA cache_size = <val>. |
_loc | auto atau zona waktu IANA (mis. UTC, Asia/Seoul) | Mengurai kolom teks DATETIME/TIMESTAMP ke dalam *time.Time di lokasi target. |
mode | ro, rw, rwc, memory | Menetapkan SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, atau SQLITE_OPEN_MEMORY. |
_case_sensitive_like, _query_only, _recursive_triggers, _secure_delete, _AutoVacuum | Boolean atau bilangan bulat mode | Menerapkan PRAGMA sesi yang sesuai pada inisialisasi koneksi. |
Mengubah Isolasi Proses Menjadi Keuntungan Throughput
Sekilas, menjalankan SQLite dalam proses terpisah terdengar lebih lambat daripada memanggil sqlite3_step dalam proses melalui cgo. Dalam praktiknya, hal sebaliknya terjadi segera setelah kueri mengembalikan lebih dari satu baris.
Biaya Tersembunyi dari Panggilan cgo Baris demi Baris
Dalam driver SQLite cgo konvensional, database/sql mendorong iterasi satu baris dan satu kolom pada satu waktu. Membaca 1.000 baris dengan 4 kolom memicu:
- 1.000 panggilan
cgokesqlite3_step - 4.000 panggilan
cgokesqlite3_column_typedansqlite3_column_int64/sqlite3_column_text - Ribuan persimpangan batas individual antara penjadwal Go dan tumpukan C
Request Pipelining dan Prefetching Batch 64 KiB
gosuda.org/sqlite3 menghilangkan persimpangan batas per baris dengan merancang ulang protokol jaringan di sekitar dua mekanisme dalam stmt.go, rows.go, dan sqlite3/server/sqlite3_hooks.c:
1Go Client (stmt.go / rows.go) C11 Worker (sqlite3_hooks.c)
2----------------------------- ----------------------------
31. Pipeline in 1 flight:
4 ResetAsync + BindValuesAsync
5 + StmtInfoAsync + FetchRowsAsync(128) =======> reset -> bind -> stmt_info ->
6 loop sqlite3_step() up to 128 rows
7 <======= Batch 1 (rows 1..128 packed in 64 KiB slot)
82. Immediately fire prefetch:
9 FetchRowsAsync(128) (Batch 2) =======> loop sqlite3_step() for rows 129..256
10 While C steps Batch 2, Go caller
11 scans rows 1..128 from Batch 1! <======= Batch 2 ready in shared memory
- Pipelining Kueri Penerbangan-Tunggal (
stmt.go): KetikaQueryContextatauStmt.QueryContextmenjalankan pernyataan baca-saja,s.query()mengirimkanreset,bind_values,stmt_info(pada eksekusi pertama), danfetch_rowssecara asinkron dalam satu penerbangan memori bersama. Keempat operasi tersebut dieksekusi secara berturut-turut pada pekerja C dan kembali dalam satu perjalanan pulang pergi. - Perulangan Batch C yang Ketat dan Prefetch Asinkron (
rows.go): Di dalamfetch_rows(sqlite3_hooks.c), pekerja C menjalankan langkahsqlite3_step(stmt)dalam perulangan C asli, mengenkode hingga barisFetchSize(bawaan 128) secara langsung ke dalam slot respons memori bersama 64 KiB hingga batas batch tercapai, slot penuh, atauSQLITE_DONEterjadi. Segera setelahrows.ingest()mendekode Batch 1, fungsi tersebut memicuFetchRowsAsyncuntuk Batch 2 sebelum mengembalikan baris pertama ke pemanggil. Saat kode Go Anda memindai Batch 1, pekerja C sudah melangkah ke Batch 2 pada inti CPU lain.
Pada Apple M4 (darwin/arm64), membandingkan gosuda.org/sqlite3 (CGO_ENABLED=0) dengan github.com/mattn/go-sqlite3 (CGO_ENABLED=1) pada basis data SQLite yang sama menunjukkan efek dari pembersihan batch dan pipelining:
| Beban Kerja | gosuda.org/sqlite3 (CGO_ENABLED=0) | mattn/go-sqlite3 (CGO_ENABLED=1) | Kecepatan Relatif |
|---|---|---|---|
Point Select (QueryRow oleh PK) | 3.52 ยตs/op (9 B, 1 alokasi) | 3.56 ยตs/op (232 B, 11 alokasi) | 1,01x (paritas, 11x alokasi lebih sedikit) |
Pindaian 100-Baris (rows.Next) | 20.41 ยตs/op (30.5 KB, 211 alokasi) | 36.34 ยตs/op (21.8 KB, 309 alokasi) | 1,78x lebih cepat |
Pindaian 1.000-Baris (rows.Next) | 125.92 ยตs/op (296 KB, 2.030 alokasi) | 349.10 ยตs/op (216 KB, 3.009 alokasi) | 2,77x lebih cepat |
| Sisipan Disiapkan (Autocommit) | 5.33 ยตs/op (0 B, 0 alokasi) | 5.88 ยตs/op (120 B, 5 alokasi) | 1,10x lebih cepat (0 alokasi) |
| Batch Transaksi 100-Baris | 189.99 ยตs/op (16 B, 1 alokasi) | 191.50 ยตs/op (12.1 KB, 503 alokasi) | 1,01x (500x alokasi lebih sedikit) |
Pembatalan, Penyekatan Jalur, dan Pemulihan Kumpulan Koneksi
Menjalankan SQLite dalam pekerja terisolasi juga memperkuat cara driver menangani batas waktu, SQL yang tidak tepercaya, dan batas sistem berkas:
- Pembatalan Konteks Deterministik (
conn.godanerrors.go): Setiap panggilan driver mempersenjatai pelindungcontext.AfterFuncyang ringan (cn.guard). Jikacontext.Contextpemanggil dibatalkan atau batas waktunya kedaluwarsa saat kueri rekursif yang lambat atau penantian kunci sedang berjalan di server, pelindung menandai koneksi rusak, mematikan tautan sesi lokal, dan mengirimkan bingkaiCancel()luar-band. Pekerja C memanggilsqlite3_interrupt(db)seketika, membuka blokirsqlite3_step, sementara driver Go memetakan statusSQLITE_INTERRUPTyang dihasilkan kecontext.Canceledataucontext.DeadlineExceededdan menginstruksikandatabase/sqluntuk mengganti koneksi dalam kumpulan. - Penyekatan Direktori (
sqlsrv_pathrules.c): Pekerja C memberlakukan aturan jalur--allow-dirpada setiap panggilanopen_v2, menyelesaikan tautan simbolik dan menolak penelusuran..relatif di luar direktori yang diizinkan.sqlite3_load_extensiondanSQLITE_LIMIT_ATTACHEDdinonaktifkan secara bawaan sehingga suntikan SQL tidak dapat lolos dari direktori basis data atau memuat objek bersama arbitrer.
Tata Letak Repositori
Repositori distrukturkan sedemikian rupa sehingga paket tingkat atas menyediakan driver database/sql langsung sementara launcher/ dan sqlite3/ tetap dapat diakses untuk penerapan server kustom tingkat lanjut:
1gosuda.org/sqlite3
2โโโ driver.go / api.go # registrasi driver database/sql ("sqlite3") dan API Konektor
3โโโ dsn.go # Pengurai DSN mattn/go-sqlite3 ruang bersih dan konfigurasi pragma
4โโโ conn.go / tx.go # Siklus hidup sesi, pelindung konteks, dan mesin status transaksi
5โโโ stmt.go / rows.go # Pipelining permintaan penerbangan-tunggal dan prefetch batch 64 KiB
6โโโ errors.go # Kode galat primer/ekspektasi SQLite bertipe dan pencocokan sentinel
7โโโ autolaunch.go / hashes.go # Mewujudkan server tersemat konfigurasi-nol dan penyematan SHA-256
8โโโ internal/embedded/ # Biner bertag platform //go:embed (linux, darwin, windows)
9โโโ launcher/ # Pengawas proses yang dapat dikonfigurasi untuk penerapan server kustom
10โโโ sqlite3/ # Klien Go hqq-bindgen yang dihasilkan dan sumber server C11 SQLite
11 โโโ server/ # Implementasi server C11 (sqlite3_hooks.c, sqlsrv_policy.c)
Memulai
Instal modul dengan go get dan buka basis data Anda dengan sql.Open("sqlite3", dsn):
1go get gosuda.org/sqlite3@v0.3.3540100
- Repositori GitHub: https://github.com/gosuda/hqq-sqlite3
- Referensi DSN & Pragma: docs/DSN.md
- Arsitektur & Protokol Jaringan: docs/ARCHITECTURE.md