Back to News
Advertisement
Advertisement

⚡ Community Insights

Discussion Sentiment

63% Positive

Analyzed from 1322 words in the discussion.

Trending Topics

#sqlite#per#polling#process#millisecond#every#need#https#select#database

Discussion (46 Comments)Read Original on HackerNews

tptacekabout 5 hours ago
"Idle cost is that one lightweight SELECT per millisecond per database — no page-cache pressure, no writer-lock contention, no kernel file watcher in the mix."

I think (respectfully) the LLM that probably wrote this overshot the mark here because busy-polling a select does not actually sound better to me than a "kernel file watcher".

russellthehippo39 minutes ago
Respectfully (thanks haha) - yeah probably right. Original intent was to use inotify type thing but i avoided per-platform differences at the outset. this was definitely a for fun project that blew up unintentionally and am working to harden/improve.

Love Fly.

felooboolooombaabout 5 hours ago
"one lightweight SELECT per millisecond"

This reminds me of the teenager who told her dad that she was just a tiny little bit pregnant.

nine_k21 minutes ago
One cannot be a little bit pregnant. But a DB can be only a little bit in the RAM, and specifically in the page cache. SQLite can act exactly like that, and it's damn fast as long as it does not need to durably write a transaction. Polling once a millisecond could spend a few microseconds.

I wonder if using a tiny Redis instance, or even something like LevelDB would be even more efficient.

srousseyabout 1 hour ago
Thing of the battery!

(read that in the way of "think of the children!")

8noteabout 2 hours ago
to me it sounds like they asked it to not make a kernel file watcher, and now it writes that into every comment everywhere, despite not even being in the implementation
russellthehippo38 minutes ago
Yup
ncrucesabout 5 hours ago
If you're not making any changes to the database, does the SELECT "kill" you?

And if you are making changes, don't you have to poll regardless after the file watcher wakes you?

For WAL mode, SQLite can probably satisfy this query just by inspecting some shared memory. But it is busy waiting, sure.

billywhizzabout 2 hours ago
SQLite has a wal hook which calls you back every time a transaction is committed to the WAL. https://www.sqlite.org/c3ref/wal_hook.html
ncrucesabout 2 hours ago
That only catches changes made by the database connection being "hooked."

This has a thread running in the background trying to catch changes made by other connections, potentially (I'm not sure here, but I suspect as much) in different processes that are modifying the same database.

d1labout 5 hours ago
Yeah, I had the same instinct - this feels very much like a "nice idea" but the execution falls short. I mean - busily banging on sqlite like this? Shit at that point just use Redis.
koito17about 4 hours ago
For what it's worth, Kine (software that k3s uses to replace etcd with SQL databases) implements etcd watches on SQLite through polling[1]. The reason being that SQLite does not offer NOTIFY/LISTEN like MySQL and Postgres do. Ironically, Honkey attempts implementing NOTIFY/LISTEN through polling.

k3s has been running on my home server for about three years now (using the default SQLite backend), and there doesn't seem to be excessive CPU usage despite dozens of watches existing in the simulated etcd. Of course, this doesn't say much about Honker, but it's nonetheless worth pointing out that sometimes the choice of database forces one towards a certain design.

[1] https://github.com/k3s-io/kine/blob/648a2daa/pkg/logstructur...

jallmannabout 3 hours ago
With SQLite, you're basically funneled towards a single-writer / single-process design anyway ... in which case why not use a more traditional condvar + mutex rather than polling?
srousseyabout 1 hour ago
Are you trying to avoid sleep?
tptacekabout 4 hours ago
I'm not even saying it's unworkable, just, my intuition is not that the "lightweight per-millisecond select" is an optimal design.
giraffe_ladyabout 4 hours ago
Really might be in sqlite. I've learned to never trust my intuition about performance with that thing. So many times I've gone to "optimize" something and discovered that the naive hack way I had been doing it was faster anyway. It's built for this sort of bullshit.
andaiabout 4 hours ago
What's the CPU usage? Like 2%?

I had a manual fs polling thing a while back. It was ugly (low time budget, didn't wanna mess with the native watchers), just scanned the whole thing once per second. It averaged out to like 0.3% CPU.

Not elegant, but acceptable for my purposes! (Small-ish directory, and "ping me within a second or two" was realtime enough for this use case.)

booiabout 2 hours ago
i mean, technically this is once per millisecond, so this would happen 1000x more. In your case due to the kernel overhead you would likely not even be able to do it (300% CPU?).

Either way this does seem like a very large overhead due to the fact that there's just no other way to do it without a deeper kernel integration which might be outside the scope of what sqlite is trying to do.

paulddraperabout 2 hours ago
> one lightweight SELECT per millisecond

For the low, low cost of $1 per minute, you can also lease a supercar.

kgeist13 minutes ago
>honker polls SQLite’s PRAGMA data_version every millisecond

I don't understand why you need busy polling if you're in-process anyway (what you usually have with Sqlite). Just make the event processing thread wait on a condition and wake it up after a transaction commits. In my Sqlite-based pet project, I have a Transaction interface that keeps track of whether an event was actually published inside a transaction, and if it was, the event processing thread is immediately notified inside Commit() to wake up and issue SELECTs. When no events are published, the Sqlite database is not touched and CPU has zero usage. Additionally, on application startup, we need to SELECT in case some events were written to the queue but did not have the chance to be processed because the application restarted or crashed.

codedokodeabout 2 hours ago
> Once real work flows through a SQLite-backed app, you need a queue. The usual answer is “add Redis + Celery.”

Are they joking? SQLite is usually used for single-process (mutliple threads) applications. The proper way to communicate between threads/processes is a ring buffer, where you allocate structs (allocation typically is incrementing a pointer), and futex/eventfd for notifications (+ some spinlocking to avoid going to kernel when the tasks arrive quickly). Why do you need redis for that? If you need persistent tasks, then you can store them in the table, and still use futex for notifications. This polling is inefficient and they should not make it a library which will cause other lazy developers add it to their app.

> honker polls SQLite’s PRAGMA data_version every millisecond. That’s a monotonic counter SQLite increments on every commit from any connection, journal mode, or process — a ~3 µs read for a precise wake signal

That's 3 ms per second = 0.3% CPU time wasted for every waiting thread.

Like Electron, this feels like written by a web developer and not a real programmer.

Groxxabout 1 hour ago
>That's 3 ms per second = 0.3% CPU time wasted for every waiting thread.

I suspect that's actually "per process, per database (usually 1)", and not based on number of threads or tables. `data_version` semantics mean there's no need for more than one connection polling it, and it's being used as a relatively lightweight "DB has changed, check queues" check (that's pretty much its whole purpose).

Also I believe this is mostly intended for multi-process use, e.g. out-of-process workers, so an in-process dirty tracker (e.g. just check after insert/update/delete) isn't sufficient.

So I do think it's somewhat crazy, but it is at least very simple. fsnotify-like monitoring seems like a fairly obvious improvement tho, not sure why that isn't part of it. Maybe it's slower? I haven't tried to do anything actually-performant-or-reliable with fs notifications, dunno what dragons lie in wait.

deepsunabout 1 hour ago
Nevertheless, expect articles like "We replaced our redis cluster with this simple extension and got it N times faster".
opiniateddev11 minutes ago
Why not just use https://github.com/conductor-oss/python-sdk provide durability, distributed and orchestration.
kweiza4 minutes ago
On edge this misses Durable Objects + alarms — same primitives, no polling, no Redis to skip in the first place.
russellthehippoabout 1 hour ago
Author here - previously posted here: https://news.ycombinator.com/item?id=47874647

Key difference vs SQL polling is that we’re touching metadata instead of data pages. I have work in process to make this work without any polling (innotify, kqueue, mmap’d shm file check) after the original stat(2) direction proved unreliable if lightweight.

Would love your feedback and or contributions in the repo - still figuring out the end shape.

EvanAndersonabout 6 hours ago
Prior discussion a few days ago: https://news.ycombinator.com/item?id=47874647
itopaloglu83about 6 hours ago
It’s an interesting approach and can be quite fun to use for new projects.

> How it works: honker polls SQLite’s PRAGMA data_version every millisecond. That’s a monotonic counter SQLite increments on every commit from any connection, journal mode, or process — a ~3 µs read for a precise wake signal.

wmanleyabout 2 hours ago
I've implemented something similar in the past, but using inotify. You need to watch the -wal file for IN_MODIFY. To make it work reliably I found I had to run:

    BEGIN IMMEDIATE TRANSACTION; ROLLBACK;
Otherwise the new changes weren't guaranteed to be visible to the process. I'm sure there's a more targetted approach that would work instead - maybe flock on a particular byte in the `-shm` file.
vmspabout 5 hours ago
Reminds me of Litestack for Rails. Eventually, it was abandoned because Rails itself started going all out on SQLite.

https://github.com/oldmoe/litestack

nop_slideabout 5 hours ago
All in*
arlobishabout 5 hours ago
At the end it says: "pg-boss and Oban are the Postgres-side gold standards" -- but Oban supports SQLite now too https://github.com/oban-bg/oban
odie5533about 3 hours ago
There's also Graphile Worker. https://github.com/graphile/worker
Advertisement
maxdoabout 3 hours ago
Almost feels like someone is trying to joke about similar postgres application .

To make it look even more absurd . SQLite is not concurrent and you’ll have tons of problems using it practically .

deferredgrantabout 3 hours ago
This seems especially appealing in the awkward middle: too serious for in-memory queues, not big enough to justify Kafka-shaped machinery.
andrewstuartabout 3 hours ago
Suggestion for the author wind back the polling to once a second when nothing is happening.
andrewstuartabout 3 hours ago
I can’t see any benchmarks or performance stats.

I’d like to see messages per second.

canadiantimabout 4 hours ago
Could this work with Turso, the SQLite rust rewrite?
russellthehippo36 minutes ago
Author here. Yeah doesn’t depend on the underlying db if it speaks SQLite.