mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-14 11:40:38 +00:00
fix lsn comparison logic
Signed-off-by: Yuchen Liang <yuchen@neon.tech>
This commit is contained in:
@@ -4278,6 +4278,52 @@ mod tests {
|
||||
tline.freeze_and_flush().await.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_lsn_leases() -> anyhow::Result<()> {
|
||||
let (tenant, ctx) = TenantHarness::create("test_lsn_leases")?.load().await;
|
||||
let key = Key::from_hex("010000000033333333444444445500000000").unwrap();
|
||||
|
||||
let timeline = tenant
|
||||
.create_test_timeline_with_layers(
|
||||
TIMELINE_ID,
|
||||
Lsn(0x10),
|
||||
DEFAULT_PG_VERSION,
|
||||
&ctx,
|
||||
Vec::new(),
|
||||
vec![
|
||||
(Lsn(0x20), vec![(key, test_img("data key 0"))]),
|
||||
(Lsn(0x30), vec![(key, test_img("data key 1"))]),
|
||||
(Lsn(0x40), vec![(key, test_img("data key 2"))]),
|
||||
],
|
||||
Lsn(0x40),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let _ = timeline.make_lsn_lease(Lsn(0x30), &ctx)?;
|
||||
|
||||
let gc_info = timeline.gc_info.read().unwrap();
|
||||
assert!(gc_info.leases.contains_key(&Lsn(0x30)));
|
||||
info!("GcCutOff: {:?}", gc_info.cutoffs);
|
||||
let res = tenant
|
||||
.gc_iteration(
|
||||
Some(TIMELINE_ID),
|
||||
0,
|
||||
Duration::ZERO,
|
||||
&CancellationToken::new(),
|
||||
&ctx,
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(res.layers_needed_by_leases, 1);
|
||||
|
||||
// 1. Setup tenant and timeline
|
||||
// 2. Make LSN lease for an LSN.
|
||||
// 3. Create two layers:
|
||||
// - one can be GC-ed, one cannot be GC-ed
|
||||
// 4. Run GC, check `GCResult`.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_prohibit_branch_creation_on_garbage_collected_data() -> anyhow::Result<()> {
|
||||
let (tenant, ctx) =
|
||||
|
||||
@@ -4907,22 +4907,22 @@ impl Timeline {
|
||||
return Err(GcError::TimelineCancelled);
|
||||
}
|
||||
|
||||
let (horizon_cutoff, pitr_cutoff, retain_lsns, max_lsn_with_valid_lease) = {
|
||||
let (horizon_cutoff, pitr_cutoff, retain_lsns, min_lsn_with_valid_lease) = {
|
||||
let gc_info = self.gc_info.read().unwrap();
|
||||
|
||||
let horizon_cutoff = min(gc_info.cutoffs.horizon, self.get_disk_consistent_lsn());
|
||||
let pitr_cutoff = gc_info.cutoffs.pitr;
|
||||
let retain_lsns = gc_info.retain_lsns.clone();
|
||||
|
||||
// Gets the maximum LSN that holds the valid lease.
|
||||
// Gets the minimum LSN that holds the valid lease.
|
||||
// Caveat: This value could be stale since we rely on refresh_gc_info to invalidate leases,
|
||||
// so there could be leases invalidated between the refresh and here.
|
||||
let max_lsn_with_valid_lease = gc_info.leases.last_key_value().map(|(lsn, _)| *lsn);
|
||||
let min_lsn_with_valid_lease = gc_info.leases.last_key_value().map(|(lsn, _)| *lsn);
|
||||
(
|
||||
horizon_cutoff,
|
||||
pitr_cutoff,
|
||||
retain_lsns,
|
||||
max_lsn_with_valid_lease,
|
||||
min_lsn_with_valid_lease,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -4959,7 +4959,7 @@ impl Timeline {
|
||||
pitr_cutoff,
|
||||
retain_lsns,
|
||||
new_gc_cutoff,
|
||||
max_lsn_with_valid_lease,
|
||||
min_lsn_with_valid_lease,
|
||||
)
|
||||
.instrument(
|
||||
info_span!("gc_timeline", timeline_id = %self.timeline_id, cutoff = %new_gc_cutoff),
|
||||
@@ -4978,7 +4978,7 @@ impl Timeline {
|
||||
pitr_cutoff: Lsn,
|
||||
retain_lsns: Vec<Lsn>,
|
||||
new_gc_cutoff: Lsn,
|
||||
max_lsn_with_valid_lease: Option<Lsn>,
|
||||
min_lsn_with_valid_lease: Option<Lsn>,
|
||||
) -> Result<GcResult, GcError> {
|
||||
// FIXME: if there is an ongoing detach_from_ancestor, we should just skip gc
|
||||
|
||||
@@ -5082,7 +5082,7 @@ impl Timeline {
|
||||
}
|
||||
|
||||
// 3.5 Is there a valid lease that requires us to keep this layer?
|
||||
if let Some(lsn) = &max_lsn_with_valid_lease {
|
||||
if let Some(lsn) = &min_lsn_with_valid_lease {
|
||||
if &l.get_lsn_range().start <= lsn {
|
||||
debug!(
|
||||
"keeping {} because there is a valid lease preventing GC at {}",
|
||||
|
||||
Reference in New Issue
Block a user