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:
Eric Seppanen
2021-07-13 17:45:45 -07:00
parent c3833ef0f4
commit 93b2e49939
5 changed files with 29 additions and 19 deletions

1
Cargo.lock generated
View File

@@ -1972,6 +1972,7 @@ dependencies = [
"anyhow",
"aversion",
"bookfile",
"hex",
"rand",
"serde",
"structopt",

View File

@@ -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"

View File

@@ -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()
};

View File

@@ -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,
};

View File

@@ -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.
///