this is a connection pool of size 1. it's also extremely in the way of
making store methods async since all methods are necessarily entangled
with all other methods via this blocking connection pool. we also will
not be able to convert *all* public methods to async code at once (not
without losing what little remains of our sanity, anyway). we'll treat
the connection pool as unbounded for a while, until the conversion has
been completed. if it turns out to be too expensive to keep db handles
in a pool like this we can tune it back down to small, or even size 1.
Change-Id: I0f3adb66df6f45a84e480c090d6627a368917db5
processGraph is not always safe to use in async code, but whether that's
the case depends on whether the caller is holding locks or not. (-sigh-)
Change-Id: Ieecea9c6d3c6abae222332bc6e3869bfd97631dd
this could be a method of AsyncCollect, but putting there would require
another overload that synthesizes the empty key types we use here. even
then a separate function is slightly nicer because it spares us writing
things like `asyncCollect(someIterableOfPromises).collect()` or similar
Change-Id: Ia92abc105016414a2171e237f2a0bc6233d3ccbf
more precisely, split it into store preparation (which remains in the
constructor proper), db initialization, and prepared statements init.
this will let us more easily turn the dbState into a connection pool.
Change-Id: I894acd4553bc83a2d86229922b757c573e394cac
this is one of the cases retrySQLite is supposed to handle. with busy
timeouts set at the connection level we may instead wait for up to an
hour to acquire locks before actually falling back to the retrySQLite
loop, blocking an entire thread in the process. this isn't painful in
the current system that uses dedicated threads for everything, but an
async executor actually suffers. since we use sqlite in WAL mode, and
WAL mode still allows reads to happen concurrently with writes, we'll
want to not block an executor on sqlite write locks. (note that while
we do have a mutex around db access that mutex is only held inside of
retrySQLite callbacks, so it will be released where we'd block today)
do note that we don't disable the timeout completely since that could
drastically reduce write performance. multiple daemon processes using
the same database file will naturally conflict, but each write is not
usually that expensive. going to sleep immediately instead of waiting
a bit can greatly impact throughput. waiting for 50ms should be fine.
Change-Id: I2d8e36ed7a0183bbc213490ebde2c79fc6e2f4b2
this is like a condition variable associated with the mutex. it's all
we'll need for the async transition, so we don't add a separate type.
Change-Id: Id9aefadd3b50e5f14f7b4d6bad41721f5249ce59
sadly this is a visitor-only interface; async generators are not yet a
thing and preliminary benchmarks say that overhead would be too large.
Change-Id: I0460d18eba94441cf3101d46bfffdb69cdda81d1
we could have constructed a nar accessor from an index just as well, but
we don't need any of the advanced accessor features like retrieving file
contents or full path-string based access to the archive. using an index
directly is simpler and faster, although in practice we shouldn't notice
Change-Id: Ic521536cd89e88cbe5aba4f26bf40f0c40d09341
this lives with the NarAccessor (for now) because only the nar accessor
consumes this format in-tree, and produces the same format for a second
type of data source (an FSAccessor instead of a precomputed nar index).
Change-Id: I54cddcf59a4e0501b5cc296c606f063feee5fb3b
we'll use this in NarAccessor to provide actually safe indexing of
archives. NarAccessor currently is not fully correct: it relies on
the parser not buffering anything to produce correct file offsets,
but only the nar implementation itself can reasonably expect that.
Change-Id: I64f300b86d8844b876a3ace723546ea7d7b4628b