This is accomplished by locking the entire database, and keeping it locked
until the last reference is unlocked. We get rid of per-reference locks,
because those are what cause race conditions.
Note that Db has the potential to deadlock when caching is being used,
and when caching isn't being used, an inconsistent state can occur. Future
changes to Db will fix both of these issues.
This commit should fix user interactive authentication for dummy flows,
but I still have to implement a few more flows, including passwords and
refresh token. I also have to fix the cleanup logic: when do we purge
UIA sessions?
This makes it much more flexible, at the expense of making it a little
more fragile. I can think of a number of scenarios where we'll have
paths that have variables in multiple spots, and I don't want to do
sprintf() magic every time I need to access an object at one of those
paths.
This requires hanging onto an open file handle, and doesn't require
explicit unlocking, because POSIX says files are unlocked when their
descriptors are closed.
- Items that are too big for the cache are now no longer immediately
evicted; everything else is. This is probably not desirable, but it is
not unexpected.
- Multithreading now should work as expected; DbRefs are locked before
they are updated from the disk, and they are not evicted from the cache
if they are locked by another thread.
- The cache may be no smaller than 1024 bytes. Previously the caller of
DbOpen() could choose to disable the cache, and provisions were made in
the code to support this, but this is now no longer possible because
without the cache, there would be no way to know what files were open,
which could lead to a race condition if two threads open the same file.