From 4227cfc96eda8ddde3c4b4df51efac6f0f1fc8c0 Mon Sep 17 00:00:00 2001 From: Konstantin Knizhnik Date: Tue, 9 Aug 2022 22:45:33 +0300 Subject: [PATCH] Safe truncate (#2218) * Move relation sie cache to layered timeline * Fix obtaining current LSN for relation size cache * Resolve merge conflicts * Resolve merge conflicts * Reestore 'lsn' field in DatadirModification * adjust DatadirModification lsn in ingest_record * Fix formatting * Pass lsn to get_relsize * Fix merge conflict * Update pageserver/src/pgdatadir_mapping.rs Co-authored-by: Heikki Linnakangas * Update pageserver/src/pgdatadir_mapping.rs Co-authored-by: Heikki Linnakangas * Check if relation exists before trying to truncat it refer #1932 * Add test reporducing FSM truncate problem Co-authored-by: Heikki Linnakangas --- pageserver/src/pgdatadir_mapping.rs | 25 +++++++++++-------- test_runner/batch_others/test_fsm_truncate.py | 11 ++++++++ vendor/postgres | 2 +- 3 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 test_runner/batch_others/test_fsm_truncate.py diff --git a/pageserver/src/pgdatadir_mapping.rs b/pageserver/src/pgdatadir_mapping.rs index 9097a08d05..827bd29ded 100644 --- a/pageserver/src/pgdatadir_mapping.rs +++ b/pageserver/src/pgdatadir_mapping.rs @@ -708,20 +708,25 @@ impl<'a, T: DatadirTimeline> DatadirModification<'a, T> { /// Truncate relation pub fn put_rel_truncation(&mut self, rel: RelTag, nblocks: BlockNumber) -> Result<()> { ensure!(rel.relnode != 0, "invalid relnode"); - let size_key = rel_size_to_key(rel); + let last_lsn = self.tline.get_last_record_lsn(); + if self.tline.get_rel_exists(rel, last_lsn)? { + let size_key = rel_size_to_key(rel); + // Fetch the old size first + let old_size = self.get(size_key)?.get_u32_le(); - // Fetch the old size first - let old_size = self.get(size_key)?.get_u32_le(); + // Update the entry with the new size. + let buf = nblocks.to_le_bytes(); + self.put(size_key, Value::Image(Bytes::from(buf.to_vec()))); - // Update the entry with the new size. - let buf = nblocks.to_le_bytes(); - self.put(size_key, Value::Image(Bytes::from(buf.to_vec()))); + // Update relation size cache + self.tline.set_cached_rel_size(rel, self.lsn, nblocks); - // Update relation size cache - self.tline.set_cached_rel_size(rel, self.lsn, nblocks); + // Update relation size cache + self.tline.set_cached_rel_size(rel, self.lsn, nblocks); - // Update logical database size. - self.pending_nblocks -= old_size as isize - nblocks as isize; + // Update logical database size. + self.pending_nblocks -= old_size as isize - nblocks as isize; + } Ok(()) } diff --git a/test_runner/batch_others/test_fsm_truncate.py b/test_runner/batch_others/test_fsm_truncate.py new file mode 100644 index 0000000000..0f85942598 --- /dev/null +++ b/test_runner/batch_others/test_fsm_truncate.py @@ -0,0 +1,11 @@ +from fixtures.log_helper import log +from fixtures.neon_fixtures import NeonEnv, NeonEnvBuilder, NeonPageserverHttpClient +import pytest + + +def test_fsm_truncate(neon_env_builder: NeonEnvBuilder): + env = neon_env_builder.init_start() + env.neon_cli.create_branch("test_fsm_truncate") + pg = env.postgres.create_start('test_fsm_truncate') + pg.safe_psql( + 'CREATE TABLE t1(key int); CREATE TABLE t2(key int); TRUNCATE TABLE t1; TRUNCATE TABLE t2;') diff --git a/vendor/postgres b/vendor/postgres index 5280b6fe10..bc6dcc493c 160000 --- a/vendor/postgres +++ b/vendor/postgres @@ -1 +1 @@ -Subproject commit 5280b6fe1027afd5a7e14c142913d9fdf9e2b442 +Subproject commit bc6dcc493c977f3b06ad95abf493273a693b0e12