Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

edge case of read_biased setter: intended behavior? #22

Open
richardsheridan opened this issue Oct 3, 2023 · 0 comments
Open

edge case of read_biased setter: intended behavior? #22

richardsheridan opened this issue Oct 3, 2023 · 0 comments

Comments

@richardsheridan
Copy link

I'm implementing a layer of a database, and I'm thinking about relying on a specific corner case of the read_biased setter. In this situation, the DB is going to flush a bunch of cached writes to disk, but I want to allow readers to view the cached data during that time, while simultaneously have writers queue up on the lock so the cache doesn't mutate during the flush.

Specific code if interested
class SomeCustomDB:
    lock = tricycle.RWLock()

    ...

    @contextlib.asynccontextmanager
    async def write_tx(self):
        async with self.lock.write_locked():
            self.lock.read_biased = False
            token = self.checkpoint()
            try:
                yield
            except BaseException as e:
                self.restore(token)
                raise e
            finally:
                # need opportunity to flush even after rollback
                # previous chained writes may have modified the cache
                if self.lock.statistics().writers_waiting == 0:
                    self.lock.read_biased = True
                    with trio.CancelScope(shield=True):
                        await self.aflush()
                else:
                    await trio.lowlevel.cancel_shielded_checkpoint()

I thought that setting self.lock.read_biased = True while holding the write lock would just change the behavior after the lock is dropped, but it has the effect of calling _wake_all_readers, meaning a bunch of readers think they've aquired the lock and start running. But any new readers during the flush will block when acquiring the lock, because _writer is not None so acquire_nowait would raise WouldBlock.

This is all a bit weird, but it happens to be exactly what I want. I could possibly achieve my goal by dropping the lock, setting read_biased = True outside the lock, and re-acquiring it for read to do my flush, so I'm good either way, but I wanted to point out this edge case in the event you wanted to either canonize it or fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant