mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-09 06:22:57 +00:00
remove snapshot id; replace with timeline id
The snapshot id doesn't make sense when two snapshots are squashed. Better to use the timeline id anyway. It's still a little strange to squash two timelines together, but it must be possible to flatten history even if there have been many branch events, so this is should be a control plane / snapshot management problem.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1972,6 +1972,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"aversion",
|
||||
"bookfile",
|
||||
"hex",
|
||||
"rand",
|
||||
"serde",
|
||||
"structopt",
|
||||
|
||||
@@ -15,6 +15,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
rand = "0.8.3"
|
||||
structopt = "0.3"
|
||||
zenith_utils = { path = "../zenith_utils" }
|
||||
hex = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.2"
|
||||
|
||||
@@ -27,23 +27,27 @@ pub use versioned::{PageIndex, PageLocation, Predecessor, SnapFileMeta};
|
||||
use zenith_utils::lsn::Lsn;
|
||||
|
||||
impl SnapFileMeta {
|
||||
pub fn new(previous: Option<SnapFileMeta>, lsn: Lsn) -> Self {
|
||||
pub fn new(previous: Option<SnapFileMeta>, timeline: [u8; 16], lsn: Lsn) -> Self {
|
||||
// Store the metadata of the predecessor snapshot, if there is one.
|
||||
let predecessor = previous.map(|prev| Predecessor {
|
||||
id: prev.snap_id,
|
||||
timeline: prev.timeline,
|
||||
lsn: prev.lsn,
|
||||
});
|
||||
|
||||
let snap_id: u64 = rand::random();
|
||||
SnapFileMeta {
|
||||
snap_id,
|
||||
timeline,
|
||||
predecessor,
|
||||
lsn: lsn.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_filename(&self) -> OsString {
|
||||
format!("{:x}.zdb", self.snap_id).into()
|
||||
let timeline_string = hex::encode(self.timeline);
|
||||
let pred_lsn = match &self.predecessor {
|
||||
None => 0,
|
||||
Some(pred) => pred.lsn,
|
||||
};
|
||||
format!("{}_{:x}_{:x}.zdb", timeline_string, pred_lsn, self.lsn).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,13 +270,15 @@ mod tests {
|
||||
use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
|
||||
const TEST_TIMELINE: [u8; 16] = [99u8; 16];
|
||||
|
||||
#[test]
|
||||
fn snap_two_pages() {
|
||||
// When `dir` goes out of scope the directory will be unlinked.
|
||||
let dir = TempDir::new().unwrap();
|
||||
let snap_meta = {
|
||||
// Write out a new snapshot file with two pages.
|
||||
let meta = SnapFileMeta::new(None, Lsn(1234));
|
||||
let meta = SnapFileMeta::new(None, TEST_TIMELINE, Lsn(1234));
|
||||
let mut snap = SnapWriter::new(dir.path(), meta).unwrap();
|
||||
// Write the pages out of order, because why not?
|
||||
let page99 = [99u8; 8192];
|
||||
@@ -313,7 +319,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let snap_meta = {
|
||||
// Write out a new snapshot file with no pages.
|
||||
let meta = SnapFileMeta::new(None, Lsn(1234));
|
||||
let meta = SnapFileMeta::new(None, TEST_TIMELINE, Lsn(1234));
|
||||
let snap = SnapWriter::new(dir.path(), meta).unwrap();
|
||||
snap.finish().unwrap()
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ pub fn squash(older: &Path, newer: &Path, out_dir: &Path) -> Result<()> {
|
||||
|
||||
// Check that snap1 is the predecessor of snap2.
|
||||
match meta2.predecessor {
|
||||
Some(pred) if pred.id == meta1.snap_id => {}
|
||||
Some(pred) if pred.timeline == meta1.timeline => {}
|
||||
_ => {
|
||||
bail!(
|
||||
"snap file {:?} is not the predecessor of {:?}",
|
||||
@@ -55,11 +55,12 @@ pub fn squash(older: &Path, newer: &Path, out_dir: &Path) -> Result<()> {
|
||||
// The new combined snapshot will have most fields from meta2 (the later
|
||||
// snapshot), but will have the predecessor from meta1.
|
||||
let new_meta = SnapFileMeta {
|
||||
// FIXME: Wow, this seems wrong. Need to sort out what to do here.
|
||||
// should snap_id even exist? The fact that we plan on squashing
|
||||
// snapshots often implies that maybe they shouldn't.
|
||||
// How do we identify predecessor? timeline_id + lsn?
|
||||
snap_id: meta2.snap_id,
|
||||
// There is some danger in squashing snapshots across two timelines,
|
||||
// in that it's possible to get confused about what the history
|
||||
// looks like. Ultimately, it should be possible to squash our way
|
||||
// to a "complete" snapshot (that contains all pages), so this must
|
||||
// be possible.
|
||||
timeline: meta2.timeline,
|
||||
predecessor: meta1.predecessor,
|
||||
lsn: meta2.lsn,
|
||||
};
|
||||
|
||||
@@ -30,21 +30,22 @@ pub(crate) const CHAPTER_PAGE_INDEX: u64 = 3;
|
||||
/// of that snapshot.
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Predecessor {
|
||||
/// This is the id number of the previous snapshot.
|
||||
/// This is the ID number of the predecessor timeline.
|
||||
///
|
||||
/// This must match the snap_id of the previous snapshot.
|
||||
pub id: u64,
|
||||
/// This may match the current snapshot's timeline id, but
|
||||
/// it may not (if the precessor was the branch point).
|
||||
pub timeline: [u8; 16],
|
||||
|
||||
/// This is the LSN of the previous snapshot.
|
||||
/// This is the LSN of the predecessor snapshot.
|
||||
pub lsn: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Versioned, UpgradeLatest)]
|
||||
pub struct SnapFileMetaV1 {
|
||||
/// This is a unique ID number for this snapshot.
|
||||
/// This is a unique ID number for this timeline.
|
||||
///
|
||||
/// This number guarantees that snapshot history is unique.
|
||||
pub snap_id: u64,
|
||||
pub timeline: [u8; 16],
|
||||
|
||||
/// Information about the predecessor snapshot.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user