Hosted onseed.hyper.mediavia theHypermedia Protocol

The pool is the daemon’s shared set of open SQLite connections.

In code it is:

*sqlitex.Pool

Created around here:

backend/storage/storage.go

with size roughly:

max(runtime.NumCPU(), 12)

So the daemon keeps multiple SQLite connections open and lets different goroutines borrow one.

Why have a pool?

Because many parts of the daemon need DB access:

sync
blob indexing
peer updates
domain cache
feed/list queries
document queries

Instead of opening/closing SQLite every time, they do:

conn, release, err := pool.Conn(ctx)
defer release()

or:

db.WithTx(ctx, func(conn *sqlite.Conn) error {
  ...
})

Important point

The pool allows many DB operations to be in flight, but SQLite still allows only:

one writer at a time

So the pool may have 12+ connections, but only one connection can be actively writing.

How pool starvation happens

If many goroutines borrow connections and then wait inside:

BEGIN IMMEDIATE

they hold those pool connections while waiting for the writer lock.

Then reads may come along and need a connection:

db.Conn(ctx)

but all connections are occupied by waiting writers.

So even though WAL allows reads, reads can be delayed because they cannot get a connection from the pool.

Analogy

SQLite writer lock:

one bathroom

Connection pool:

set of keys to enter the building

If many people take all the building keys and then wait outside the bathroom, nobody else can even enter the building to use other rooms.

That is why writer contention can affect reads.

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime