Store source modified timestamp with processed, lightmap and map tiles

Allows to check whether the source is newer than the last update of the
output files.
This commit is contained in:
Matthias Schiffer 2023-07-30 21:19:24 +02:00
parent e18d4cea82
commit 628a702fd7
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
4 changed files with 75 additions and 15 deletions

View file

@ -1,4 +1,4 @@
use std::path::Path;
use std::{path::Path, time::SystemTime};
use anyhow::{Context, Result};
@ -65,14 +65,25 @@ impl<'a> RegionProcessor<'a> {
})
}
fn save_region(&self, coords: TileCoords, processed_region: &ProcessedRegion) -> Result<()> {
fn save_region(
&self,
coords: TileCoords,
processed_region: &ProcessedRegion,
timestamp: SystemTime,
) -> Result<()> {
let output_path = self.config.processed_path(coords);
storage::write(&output_path, processed_region)
storage::write(&output_path, processed_region, timestamp)
}
fn save_lightmap(&self, coords: TileCoords, lightmap: &image::GrayAlphaImage) -> Result<()> {
fs::create_with_tmpfile(
fn save_lightmap(
&self,
coords: TileCoords,
lightmap: &image::GrayAlphaImage,
timestamp: SystemTime,
) -> Result<()> {
fs::create_with_timestamp(
&self.config.tile_path(TileKind::Lightmap, 0, coords),
timestamp,
|file| {
lightmap
.write_to(file, image::ImageFormat::Png)
@ -90,6 +101,8 @@ impl<'a> RegionProcessor<'a> {
let mut processed_region = ProcessedRegion::default();
let mut lightmap = image::GrayAlphaImage::new(N, N);
let timestamp = fs::modified_timestamp(path)?;
minedmap::io::region::from_file(path)?.foreach_chunk(
|chunk_coords, data: world::de::Chunk| {
let Some(layer::LayerData{ blocks, biomes, block_light, depths }) = self
@ -111,8 +124,8 @@ impl<'a> RegionProcessor<'a> {
},
)?;
self.save_region(coords, &processed_region)?;
self.save_lightmap(coords, &lightmap)?;
self.save_region(coords, &processed_region, timestamp)?;
self.save_lightmap(coords, &lightmap, timestamp)?;
Ok(())
}

View file

@ -1,3 +1,5 @@
use std::time::SystemTime;
use anyhow::{Context, Result};
use minedmap::{
@ -17,9 +19,12 @@ impl<'a> TileRenderer<'a> {
TileRenderer { config }
}
fn load_region(&self, coords: TileCoords) -> Result<ProcessedRegion> {
fn load_region(&self, coords: TileCoords) -> Result<(ProcessedRegion, SystemTime)> {
let processed_path = self.config.processed_path(coords);
storage::read(&processed_path).context("Failed to load processed region data")
let timestamp = fs::modified_timestamp(&processed_path)?;
let region =
storage::read(&processed_path).context("Failed to load processed region data")?;
Ok((region, timestamp))
}
fn render_chunk(image: &mut image::RgbaImage, coords: ChunkCoords, chunk: &ProcessedChunk) {
@ -69,11 +74,11 @@ impl<'a> TileRenderer<'a> {
.display(),
);
let region = self.load_region(coords)?;
let (region, timestamp) = self.load_region(coords)?;
let mut image = image::RgbaImage::new(N, N);
Self::render_region(&mut image, &region);
fs::create_with_tmpfile(&output_path, |file| {
fs::create_with_timestamp(&output_path, timestamp, |file| {
image
.write_to(file, image::ImageFormat::Png)
.context("Failed to save image")

View file

@ -2,19 +2,34 @@ use std::{
fs::{self, File},
io::{BufReader, BufWriter, Read, Write},
path::{Path, PathBuf},
time::SystemTime,
};
use anyhow::{Context, Ok, Result};
use serde::Serialize;
fn tmpfile_name(path: &Path) -> PathBuf {
#[derive(Debug, Serialize)]
struct FileMeta {
timestamp: SystemTime,
}
fn suffix_name(path: &Path, suffix: &str) -> PathBuf {
let mut file_name = path.file_name().unwrap_or_default().to_os_string();
file_name.push(".tmp");
file_name.push(suffix);
let mut ret = path.to_path_buf();
ret.set_file_name(file_name);
ret
}
fn tmpfile_name(path: &Path) -> PathBuf {
suffix_name(path, ".tmp")
}
fn metafile_name(path: &Path) -> PathBuf {
suffix_name(path, ".meta")
}
pub fn create_dir_all(path: &Path) -> Result<()> {
fs::create_dir_all(path)
.with_context(|| format!("Failed to create directory {}", path.display(),))
@ -84,3 +99,29 @@ where
ret
}
pub fn modified_timestamp(path: &Path) -> Result<SystemTime> {
fs::metadata(path)
.and_then(|meta| meta.modified())
.with_context(|| {
format!(
"Failed to get modified timestamp of file {}",
path.display()
)
})
}
pub fn create_with_timestamp<T, F>(path: &Path, timestamp: SystemTime, f: F) -> Result<T>
where
F: FnOnce(&mut BufWriter<File>) -> Result<T>,
{
let ret = create_with_tmpfile(path, f)?;
let meta_path = metafile_name(path);
create(&meta_path, |file| {
serde_json::to_writer(file, &FileMeta { timestamp })?;
Ok(())
})?;
Ok(ret)
}

View file

@ -2,6 +2,7 @@ use std::{
fs::File,
io::{Read, Write},
path::Path,
time::SystemTime,
};
use anyhow::{Context, Result};
@ -9,8 +10,8 @@ use serde::{de::DeserializeOwned, Serialize};
use super::fs;
pub fn write<T: Serialize>(path: &Path, value: &T) -> Result<()> {
fs::create_with_tmpfile(path, |file| {
pub fn write<T: Serialize>(path: &Path, value: &T, timestamp: SystemTime) -> Result<()> {
fs::create_with_timestamp(path, timestamp, |file| {
let data = bincode::serialize(value)?;
let len = u32::try_from(data.len())?;
let compressed = zstd::bulk::compress(&data, 1)?;