Skip to content

Commit

Permalink
add a version to each stored path, to support format upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
timbertson committed Feb 1, 2024
1 parent 5d6a690 commit 8b2e288
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 12 deletions.
27 changes: 20 additions & 7 deletions cli/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use lazy_static::lazy_static;
use std::{fs, process::{Command, Stdio}, collections::HashSet, path::PathBuf, str::FromStr};

use crate::{paths::RuntimePaths, store::StoreMeta};
use crate::rewrite;
use crate::store::StoreIdentity;
use crate::{rewrite, store};
use crate::store::{MetaError, StoreIdentity};
use crate::serde_from_string;

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -214,11 +214,24 @@ impl Client {
// NOTE: must hold lock to call this
let dest_path = self.paths.store_path.join(entry.directory());
let meta_path = self.paths.meta_path.join(entry.directory());
if meta_path.exists() && dest_path.exists() {
debug!("Cache path already exists: {:?}", dest_path);
return Ok(None);
let meta = if meta_path.exists() && dest_path.exists() {
match StoreMeta::load(&self.paths, &entry) {
Result::Ok(meta) => Ok(Some(meta)),
Err(MetaError::UnsupportedVersion) => {
fs::remove_file(&meta_path)?;
Ok(None)
},
Err(MetaError::LoadError(e)) => {
Err(e)
},
}?
} else {
self.fetch_narinfo(entry).map(Some)
None
};

match meta {
Some(_) => Ok(None),
None => self.fetch_narinfo(entry).map(Some),
}
}

Expand Down Expand Up @@ -282,7 +295,7 @@ impl Client {
rewrite::rewrite_all_recursively(&dest, &self.paths.rewrite, &nar_info.references)?;

// create the meta file, which signifies the validity of the store path
StoreMeta::write(&self.paths, nar_info)?;
StoreMeta::write(&self.paths, nar_info, store::StoreEntryVersion::Latest)?;

info!("Fetched {}", nar_info.identity.display_name());
Ok(())
Expand Down
80 changes: 75 additions & 5 deletions cli/src/store.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::*;
use log::*;
use std::path::PathBuf;
use std::{fs, str::FromStr, fmt::Display};
use serde::{Serialize, Deserialize};
Expand All @@ -7,6 +8,36 @@ use filetime::{set_file_mtime, FileTime};
use crate::{serde_from_string, cache::NarInfo};
use crate::paths::*;

const LATEST_VERSION: i32 = 1;
// v0: original runix release
// v1: codesign on all rewritten executable files

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(from = "i32", into = "i32")]
pub enum StoreEntryVersion {
Latest,
Historical(i32),
}

impl From<i32> for StoreEntryVersion {
fn from(value: i32) -> Self {
if value == LATEST_VERSION {
Self::Latest
} else {
Self::Historical(value)
}
}
}

impl Into<i32> for StoreEntryVersion {
fn into(self) -> i32 {
match self {
Self::Latest => LATEST_VERSION,
Self::Historical(i) => i,
}
}
}

pub struct StoreIdentityNameDisplay<'a>(&'a StoreIdentity);
impl<'a> Display for StoreIdentityNameDisplay<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Expand Down Expand Up @@ -101,14 +132,39 @@ impl Display for StoreIdentity {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct StoreMeta {
pub references: Vec<StoreIdentity>,

pub version: StoreEntryVersion,
}

#[derive(Debug)]
pub enum MetaError {
UnsupportedVersion,
LoadError(anyhow::Error),
}

impl std::fmt::Display for MetaError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnsupportedVersion => f.write_str("Unsupported store entry version"),
Self::LoadError(e) => e.fmt(f),
}
}
}

impl std::error::Error for MetaError {}

impl From<Error> for MetaError {
fn from(err: Error) -> Self {
Self::LoadError(err)
}
}

impl StoreMeta {
fn path(paths: &RuntimePaths, identity: &StoreIdentity) -> PathBuf {
paths.meta_path.join(&identity.directory)
}

pub fn write(paths: &RuntimePaths, nar_info: &NarInfo<'_>) -> Result<()> {
pub fn write(paths: &RuntimePaths, nar_info: &NarInfo<'_>, version: StoreEntryVersion) -> Result<()> {
let get_dest = || Self::path(paths, nar_info.identity);
util::with_file_ctx(|| format!("Writing {}", get_dest().display()), || {
let dest = get_dest();
Expand All @@ -122,6 +178,7 @@ impl StoreMeta {
.with_context(|| format!("Writing {}", tmp_dest.display()))?;
let store_meta = StoreMeta {
references: nar_info.references.clone(),
version,
};
serde_json::to_writer(file, &store_meta)?;
util::rename(tmp_dest, dest)?;
Expand All @@ -136,19 +193,25 @@ impl StoreMeta {
})
}

pub fn load(paths: &RuntimePaths, identity: &StoreIdentity) -> Result<StoreMetaFull> {
pub fn load(paths: &RuntimePaths, identity: &StoreIdentity) -> Result<StoreMetaFull, MetaError> {
let p = Self::path(paths, identity);
util::with_file_ctx(|| format!("Loading {}", p.display()), || {
let meta = util::with_file_ctx(|| format!("Loading {}", p.display()), || {
let contents = fs::read_to_string(&p)?;
let meta = serde_json::from_str(&contents)?;
let used_timestamp = FileTime::from_last_modification_time(&fs::metadata(&p)?);
Ok(StoreMetaFull {
meta,
used_timestamp
})
})
}
})?;

if meta.is_supported() {
Result::Ok(meta)
} else {
debug!("Cache path exists but version unsupported: {:?}", &p);
Err(MetaError::UnsupportedVersion)
}
}
}

// Contents of the meta file as well as access time
Expand All @@ -164,4 +227,11 @@ impl StoreMetaFull {
pub fn references(&self) -> &Vec<StoreIdentity> {
&self.meta.references
}

pub fn is_supported(&self) -> bool {
match self.meta.version {
StoreEntryVersion::Latest => true,
StoreEntryVersion::Historical(_) => false,
}
}
}

0 comments on commit 8b2e288

Please sign in to comment.