pageserver: add GcInfo::notify_child_keyspace

This commit is contained in:
John Spray
2024-07-06 18:57:28 +01:00
parent 3a6101bd21
commit 1e392a00e4
3 changed files with 29 additions and 15 deletions

View File

@@ -19,6 +19,7 @@ use enumset::EnumSet;
use futures::stream::FuturesUnordered;
use futures::FutureExt;
use futures::StreamExt;
use pageserver_api::keyspace::KeySpace;
use pageserver_api::models;
use pageserver_api::models::AuxFilePolicy;
use pageserver_api::models::TimelineState;
@@ -2786,11 +2787,12 @@ impl Tenant {
// Scan all timelines. For each timeline, remember the timeline ID and
// the branch point where it was created.
let mut all_branchpoints: BTreeMap<TimelineId, Vec<(Lsn, TimelineId)>> = BTreeMap::new();
let mut all_branchpoints: BTreeMap<TimelineId, Vec<(Lsn, TimelineId, Option<KeySpace>)>> =
BTreeMap::new();
timelines.iter().for_each(|(timeline_id, timeline_entry)| {
if let Some(ancestor_timeline_id) = &timeline_entry.get_ancestor_timeline_id() {
let ancestor_children = all_branchpoints.entry(*ancestor_timeline_id).or_default();
ancestor_children.push((timeline_entry.get_ancestor_lsn(), *timeline_id));
ancestor_children.push((timeline_entry.get_ancestor_lsn(), *timeline_id, None));
}
});
@@ -2799,7 +2801,7 @@ impl Tenant {
// Populate each timeline's GcInfo with information about its child branches
for timeline in timelines.values() {
let mut branchpoints: Vec<(Lsn, TimelineId)> = all_branchpoints
let mut branchpoints: Vec<(Lsn, TimelineId, Option<KeySpace>)> = all_branchpoints
.remove(&timeline.timeline_id)
.unwrap_or_default();
@@ -4305,7 +4307,7 @@ mod tests {
{
let branchpoints = &tline.gc_info.read().unwrap().retain_lsns;
assert_eq!(branchpoints.len(), 1);
assert_eq!(branchpoints[0], (Lsn(0x40), NEW_TIMELINE_ID));
assert_eq!(branchpoints[0], (Lsn(0x40), NEW_TIMELINE_ID, None));
}
// You can read the key from the child branch even though the parent is

View File

@@ -271,10 +271,14 @@ pub(super) async fn gather_inputs(
let mut lsns: Vec<(Lsn, LsnKind)> = gc_info
.retain_lsns
.iter()
.filter(|(lsn, _child_id)| lsn > &ancestor_lsn)
.copied()
// this assumes there are no other retain_lsns than the branchpoints
.map(|(lsn, _child_id)| (lsn, LsnKind::BranchPoint))
.filter_map(|(lsn, _child_id, _)| {
if lsn > &ancestor_lsn {
// this assumes there are no other retain_lsns than the branchpoints
Some((*lsn, LsnKind::BranchPoint))
} else {
None
}
})
.collect::<Vec<_>>();
lsns.extend(lease_points.iter().map(|&lsn| (lsn, LsnKind::LeasePoint)));

View File

@@ -453,12 +453,12 @@ pub struct WalReceiverInfo {
/// Garbage Collection.
#[derive(Default)]
pub(crate) struct GcInfo {
/// Specific LSNs that are needed.
/// Record which parts of this timeline's history are still needed by children
///
/// Currently, this includes all points where child branches have
/// been forked off from. In the future, could also include
/// explicit user-defined snapshot points.
pub(crate) retain_lsns: Vec<(Lsn, TimelineId)>,
/// Optionally store each child's keyspace at their branch LSN: parts of the keyspace not covered here may be dropped during GC, as
/// the child will never read them. For example, a child which has covered its whole keyspace with image layers
/// will put an empty keyspace here. Children populate this: if it is None, presume the child may read any part of the keyspace.
pub(crate) retain_lsns: Vec<(Lsn, TimelineId, Option<KeySpace>)>,
/// The cutoff coordinates, which are combined by selecting the minimum.
pub(crate) cutoffs: GcCutoffs,
@@ -476,13 +476,21 @@ impl GcInfo {
}
pub(super) fn insert_child(&mut self, child_id: TimelineId, child_lsn: Lsn) {
self.retain_lsns.push((child_lsn, child_id));
self.retain_lsns.push((child_lsn, child_id, None));
self.retain_lsns.sort_by_key(|i| i.0);
}
pub(super) fn remove_child(&mut self, child_id: TimelineId) {
self.retain_lsns.retain(|i| i.1 != child_id);
}
/// When the child re-calculates which parts of the keyspace it will read from the ancestor, it posts
/// and update to the parent using this function, to enable the parent to perhaps GC more layers.
pub(super) fn notify_child_keyspace(&mut self, child_id: TimelineId, key_space: KeySpace) {
if let Ok(idx) = self.retain_lsns.binary_search_by_key(&child_id, |i| i.1) {
self.retain_lsns.get_mut(idx).unwrap().2 = Some(key_space);
}
}
}
/// The `GcInfo` component describing which Lsns need to be retained.
@@ -5089,7 +5097,7 @@ impl Timeline {
let retain_lsns = gc_info
.retain_lsns
.iter()
.map(|(lsn, _child_id)| *lsn)
.map(|(lsn, _child_id, _)| *lsn)
.collect();
// Gets the maximum LSN that holds the valid lease.