mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-15 01:12:56 +00:00
This is preliminary work for/from #4220 (async `Layer::get_value_reconstruct_data`). There, we want to switch `Timeline::layers` to be a `tokio::sync::RwLock`. The problem with `DatadirModification::flush` is that it uses `TimelineWriter::put`, and that method needs to lock `Timeline::layers` down the call tree. So, `TimelineWriter::put` will needs to become async. But `DatadirModification::flush` calls `put()` from inside the `retain` closure. That won't work once `put()` becomes async, because there are no async closures in Rust. I'm not aware of an `async`-compatible alternative for `retain`. Hence, this patch pre-locks `Timeline::layers`, then passes the guard to the closure. Deadlocks ========= `TimelineWriter::put` needs to lock `Timeline::layers` when it needs to create a new `open` layer. While we hold the `Timeline::layers` locked, the flush loop timeline task can't make progress. But the flush loop isn't running yet in these cases. So, I'm wondering, what actually happens at runtime if the bootstrap / basebackup import fills up the first `open` layer. What turns it `frozen`? Is anything flushing?