> In WAL mode SQLite is very good at supporting parallel reads from multiple threads. It should only block for a long time when writing (since writes require an exclusive lock.)
Agreed.
> It sounds like your v8 worker threads are mixing read and write work so you are running the query in another sqlite thread pool to preven> In WAL mode SQLite is very good at supporting parallel reads from multiple threads. It should only block for a long time when writing (since writes require an exclusive lock.)
Agreed.
> It sounds like your v8 worker threads are mixing read and write work so you are running the query in another sqlite thread pool to prevent writes from blocking reads.
The v8 isolates run whatever you as a TrailBase user feed them. I would certainly expect writes to be a common occurrence.
> Given the additional costs of cross-thread communication I would be surprised if this approach maximizes throughput under highly concurrent loads compared to segregating write requests into a dedicated thread and running read queries synchronously from within their threadpool with a single task per thread.
Ultimately, it will depend a lot on the ratios. If you have mostly reads and the occasional write you're probably right. I did spend a bit of time exploring different execution models: https://github.com/ignatz/libsql_bench in case you're interested. There's also some prior works from the folks GIL'ed languages (especially ruby) around how to wrangle write congestion for multi-process workloads. Sadly for them, they don't have inter-thread comms in their arsenal :)
One big unknown for me is, how you'd clearly separate reads from writes. As far as I can think, you'd have to rely on users to pick the right sync or async funnel. Which may be ok at least for simple queries.
FWIW, the thing or elephant that bothered me more than inter-thread comms is the opportunity cost of not running reads in parallel. Then at the same time, the current setup does seem to manage to saturate the machines I've run on. Very high core-count machines would probably be a different story. It will certainly also depend on how much actual other work the server has to do, i.e. is it just a glorified SQLite accessor? I certainly would love to further optimize that aspect. You seem very well informed so I'd love to hear your thoughts. Hit me up, if you'd like to chat more.t writes from blocking reads.
The v8 isolates run whatever you as a TrailBase user feed them. I would certainly expect writes to be a common occurrence.
> Given the additional costs of cross-thread communication I would be surprised if this approach maximizes throughput under highly concurrent loads compared to segregating write requests into a dedicated thread and running read queries synchronously from within their threadpool with a single task per thread.
Ultimately, it will depend a lot on the ratios. If you have mostly reads and the occasional write you're probably right. I did spend a bit of time exploring different execution models: https://github.com/ignatz/libsql_bench in case you're interested. There's also some prior works from the folks GIL'ed languages (especially ruby) around how to wrangle write congestion for multi-process workloads. Sadly for them, they don't have inter-thread comms in their arsenal :)
One big unknown for me is, how you'd clearly separate reads from writes. As far as I can think, you'd have to rely on users to pick the right sync or async funnel. Which may be ok at least for simple queries.
FWIW, the thing or elephant that bothered me more than inter-thread comms is the opportunity cost of not running reads in parallel. Then at the same time, the current setup does seem to manage to saturate the machines I've run on. Very high core-count machines may be a different story. It will certainly also depend on how much actual other work the server has to do, i.e. is it just a glorified SQLite accessor? I certainly would love to further optimize that aspect. You seem very well informed so I'd love to hear your thoughts. Hit me up, if you're willing to chat more.