mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-16 09:52:54 +00:00
Fixes https://github.com/neondatabase/neon/issues/6337 Add safekeeper support to switch between `Present` and `Offloaded(flush_lsn)` states. The offloading is disabled by default, but can be controlled using new cmdline arguments: ``` --enable-offload Enable automatic switching to offloaded state --delete-offloaded-wal Delete local WAL files after offloading. When disabled, they will be left on disk --control-file-save-interval <CONTROL_FILE_SAVE_INTERVAL> Pending updates to control file will be automatically saved after this interval [default: 300s] ``` Manager watches state updates and detects when there are no actvity on the timeline and actual partial backup upload in remote storage. When all conditions are met, the state can be switched to offloaded. In `timeline.rs` there is `StateSK` enum to support switching between states. When offloaded, code can access only control file structure and cannot use `SafeKeeper` to accept new WAL. `FullAccessTimeline` is now renamed to `WalResidentTimeline`. This struct contains guard to notify manager about active tasks requiring on-disk WAL access. All guards are issued by the manager, all requests are sent via channel using `ManagerCtl`. When manager receives request to issue a guard, it unevicts timeline if it's currently evicted. Fixed a bug in partial WAL backup, it used `term` instead of `last_log_term` previously. After this commit is merged, next step is to roll this change out, as in issue #6338.
95 lines
2.6 KiB
Rust
95 lines
2.6 KiB
Rust
use std::{collections::HashMap, sync::Arc};
|
|
|
|
use utils::id::TenantTimelineId;
|
|
|
|
use crate::timeline::Timeline;
|
|
|
|
/// Set of timelines, supports operations:
|
|
/// - add timeline
|
|
/// - remove timeline
|
|
/// - clone the set
|
|
///
|
|
/// Usually used for keeping subset of timelines. For example active timelines that require broker push.
|
|
pub struct TimelinesSet {
|
|
timelines: std::sync::Mutex<HashMap<TenantTimelineId, Arc<Timeline>>>,
|
|
}
|
|
|
|
impl Default for TimelinesSet {
|
|
fn default() -> Self {
|
|
Self {
|
|
timelines: std::sync::Mutex::new(HashMap::new()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TimelinesSet {
|
|
pub fn insert(&self, tli: Arc<Timeline>) {
|
|
self.timelines.lock().unwrap().insert(tli.ttid, tli);
|
|
}
|
|
|
|
pub fn delete(&self, ttid: &TenantTimelineId) {
|
|
self.timelines.lock().unwrap().remove(ttid);
|
|
}
|
|
|
|
/// If present is true, adds timeline to the set, otherwise removes it.
|
|
pub fn set_present(&self, tli: Arc<Timeline>, present: bool) {
|
|
if present {
|
|
self.insert(tli);
|
|
} else {
|
|
self.delete(&tli.ttid);
|
|
}
|
|
}
|
|
|
|
pub fn is_present(&self, ttid: &TenantTimelineId) -> bool {
|
|
self.timelines.lock().unwrap().contains_key(ttid)
|
|
}
|
|
|
|
/// Returns all timelines in the set.
|
|
pub fn get_all(&self) -> Vec<Arc<Timeline>> {
|
|
self.timelines.lock().unwrap().values().cloned().collect()
|
|
}
|
|
|
|
/// Returns a timeline guard for easy presence control.
|
|
pub fn guard(self: &Arc<Self>, tli: Arc<Timeline>) -> TimelineSetGuard {
|
|
let is_present = self.is_present(&tli.ttid);
|
|
TimelineSetGuard {
|
|
timelines_set: self.clone(),
|
|
tli,
|
|
is_present,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Guard is used to add or remove timeline from the set.
|
|
/// If the timeline present in set, it will be removed from it on drop.
|
|
/// Note: do not use more than one guard for the same timeline, it caches the presence state.
|
|
/// It is designed to be used in the manager task only.
|
|
pub struct TimelineSetGuard {
|
|
timelines_set: Arc<TimelinesSet>,
|
|
tli: Arc<Timeline>,
|
|
is_present: bool,
|
|
}
|
|
|
|
impl TimelineSetGuard {
|
|
/// Returns true if the state was changed.
|
|
pub fn set(&mut self, present: bool) -> bool {
|
|
if present == self.is_present {
|
|
return false;
|
|
}
|
|
self.is_present = present;
|
|
self.timelines_set.set_present(self.tli.clone(), present);
|
|
true
|
|
}
|
|
|
|
pub fn get(&self) -> bool {
|
|
self.is_present
|
|
}
|
|
}
|
|
|
|
impl Drop for TimelineSetGuard {
|
|
fn drop(&mut self) {
|
|
// remove timeline from the map on drop
|
|
self.timelines_set.delete(&self.tli.ttid);
|
|
}
|
|
}
|