Compare commits

...

4 Commits

Author SHA1 Message Date
Yuchen Liang
3221d6d248 DNM: run test_readonly_node_gc for multiple iterations
Signed-off-by: Yuchen Liang <yuchen@neon.tech>
2024-11-21 18:03:11 +00:00
John Spray
aea3c62aca pageserver: split out invalid LSN check for consistent errors 2024-11-21 13:18:09 +00:00
John Spray
fc71eb5872 tests: enable test_readonly_node_gc 2024-11-21 10:15:21 +00:00
John Spray
c7d3bd105c pageserver: permit reads behind GC cutoff while in LSN lease grace period 2024-11-21 10:14:55 +00:00
3 changed files with 21 additions and 11 deletions

View File

@@ -1068,21 +1068,26 @@ impl PageServerHandler {
));
}
if request_lsn < **latest_gc_cutoff_lsn {
// Check explicitly for INVALID just to get a less scary error message if the request is obviously bogus
if request_lsn == Lsn::INVALID {
return Err(PageStreamError::BadRequest(
"invalid LSN(0) in request".into(),
));
}
// Clients should only read from recent LSNs on their timeline, or from locations holding an LSN lease.
//
// We may have older data available, but we make a best effort to detect this case and return an error,
// to distinguish a misbehaving client (asking for old LSN) from a storage issue (data missing at a legitimate LSN).
if request_lsn < **latest_gc_cutoff_lsn && !timeline.is_gc_blocked_by_lsn_lease_deadline() {
let gc_info = &timeline.gc_info.read().unwrap();
if !gc_info.leases.contains_key(&request_lsn) {
// The requested LSN is below gc cutoff and is not guarded by a lease.
// Check explicitly for INVALID just to get a less scary error message if the
// request is obviously bogus
return Err(if request_lsn == Lsn::INVALID {
PageStreamError::BadRequest("invalid LSN(0) in request".into())
} else {
return Err(
PageStreamError::BadRequest(format!(
"tried to request a page version that was garbage collected. requested at {} gc cutoff {}",
request_lsn, **latest_gc_cutoff_lsn
).into())
});
);
}
}

View File

@@ -2085,6 +2085,11 @@ impl Timeline {
.unwrap_or(self.conf.default_tenant_conf.lsn_lease_length_for_ts)
}
pub(crate) fn is_gc_blocked_by_lsn_lease_deadline(&self) -> bool {
let tenant_conf = self.tenant_conf.load();
tenant_conf.is_gc_blocked_by_lsn_lease_deadline()
}
pub(crate) fn get_lazy_slru_download(&self) -> bool {
let tenant_conf = self.tenant_conf.load();
tenant_conf

View File

@@ -122,8 +122,8 @@ def test_readonly_node(neon_simple_env: NeonEnv):
)
@pytest.mark.skip("See https://github.com/neondatabase/neon/issues/9754")
def test_readonly_node_gc(neon_env_builder: NeonEnvBuilder):
@pytest.mark.parametrize("iter", [i for i in range(20)])
def test_readonly_node_gc(neon_env_builder: NeonEnvBuilder, iter: int):
"""
Test static endpoint is protected from GC by acquiring and renewing lsn leases.
"""