SQLR-43 — Go edge/IoT event collector (concurrent-writes showcase)#150
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
12fd190 to
3f8f472
Compare
Owner
Author
|
Amended after self-review: the first push had a failing test ( Fixed two ways and re-verified:
Added tests for both (oversized-payload rejection + a 300-row checkpoint that would otherwise blow the cap). Full suite green; e2e re-confirmed a 720-event backlog drains to 0 with no frame-cap errors. |
A Go HTTP collector that buffers telemetry from many concurrent producers into a local .sqlrite file while a background uploader goroutine drains it to a pluggable sink — both writing the same database via BEGIN CONCURRENT (Phase 11 MVCC). The fifth and final app under the SQLR-38 example-apps umbrella. What it exercises: - Go SDK (cgo via sqlrite-ffi) + the process-level sibling-handle registry, so the HTTP path and the uploader each hold their own BEGIN CONCURRENT transaction against one engine. - Row-level conflict detection + the canonical retry-on-ErrBusy loop. - A durable-buffer-for-unreliable-networks shape: survives reboots, stays queryable on-device, optional read-only sqlrite-mcp sidecar. Honest, measured framing: on the v0 engine, BEGIN CONCURRENT is ~0.9x the throughput of a single mutex and ~2x worse tail latency (global engine mutex + per-tx table clone + per-commit O(N) B-tree rebuild — all documented v0 limitations). The win demonstrated here is the capability + correctness (independent in-process writers, zero dropped events under load), not raw speed. The README ships all three measured tables (throughput / latency-under-contention / disjoint-row) and explains why, with reproduce commands. Designs around the verified v0 engine sharp edges, each found by testing: no Go-SDK param binding (inlined+escaped SQL via a single chokepoint); CREATE TABLE IF NOT EXISTS not honored + sqlrite_master not queryable (SELECT-probe for fresh-vs-reopen); CREATE INDEX rejected under MVCC (DDL before the journal_mode switch); the 4 KiB MVCC commit-record cap (payloads bounded at ingest so any single row commits, plus an adaptive checkpoint writer that halves the chunk on a cap error down to one-per-commit); and AUTOINCREMENT collisions under MVCC (app-assigned ids seeded off MAX(id)). Includes: backpressure (503) + /healthz + /stats, a load generator that asserts no drops, Dockerfile + compose (with the MCP sidecar profile), a Makefile, unit/integration tests across all packages, and a go-collector CI job (Linux + macOS) against the in-repo engine. Also: examples index + sqlritedb.com Examples card + a cross-link from docs/concurrent-writes.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3f8f472 to
a270c15
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The fifth and final app under the SQLR-38 example-apps umbrella: a Go edge/IoT event collector in
examples/go-collector/. It accepts telemetry over HTTP from many concurrent producers, buffers each event in a local.sqlritefile, and runs a background uploader goroutine that drains the buffer to a pluggable sink — both writing the same database concurrently viaBEGIN CONCURRENT(Phase 11 MVCC, SQLR-22).Blocker confirmed cleared before starting: SQLR-22 (concurrent writes) is
done; engine at v0.10.2; Go SDK exposes siblings +ErrBusy/IsRetryable.The honest headline (please read)
Concurrent writes here is a capability + correctness feature, not a throughput win. I measured it three ways and shipped the numbers as found:
BEGIN CONCURRENT)Root causes are all documented v0 limitations: global per-DB
Arc<Mutex<Database>>, per-tx double table-clone, per-commit O(N) B-tree rebuild. The genuine win — proven by the load generator — is independent in-process writers + row-level conflict detection + zero dropped events under 32 concurrent producers, which single-writer can't express. The README ships all three tables with reproduce commands and a "why it isn't faster yet" section.Designed around verified v0 engine sharp edges
Each found by testing and documented inline + in the README: no Go-SDK param binding (inlined/escaped SQL),
CREATE TABLE IF NOT EXISTSnot honored (SELECT-probe for fresh-vs-reopen),CREATE INDEXrejected under MVCC (DDL before thejournal_modeswitch), the 4 KiB MVCC commit-batch cap (chunked checkpoint commits), AUTOINCREMENT collisions under MVCC (app-assigned ids).Included
cmd/collector(HTTP + uploader),cmd/loadgen(load test + 3 measurement experiments),internal/{store,uploader,server}/healthz+/stats; pluggable + flaky sinkssqlrite-mcpsidecar against a snapshot) + Makefilego-collectorCI job (Linux + macOS) against the in-repo enginedocs/concurrent-writes.mdcross-linkVerification
cargo build -p sqlrite-ffi,gofmt -l,go vet ./...,go test ./...all clean. E2E: 627 concurrent POSTs → 627 uploaded → backlog 0, 0 dropped, clean restart-reopen with id continuation. Not run: web/examplestypecheck (nonode_modules; card mirrors existing entries) anddocker build(heavy; reviewed by hand).Follow-ups (recommended)
CREATE TABLE IF NOT EXISTSnot honored +sqlrite_masternot SQL-queryable.🤖 Generated with Claude Code