polars_io/file_cache/
metadata.rs

1use std::path::Path;
2use std::sync::Arc;
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub(super) enum FileVersion {
8    Timestamp(u64),
9    ETag(String),
10    Uninitialized,
11}
12
13#[derive(Debug)]
14pub enum LocalCompareError {
15    LastModifiedMismatch { expected: u64, actual: u64 },
16    SizeMismatch { expected: u64, actual: u64 },
17    DataFileReadError(std::io::Error),
18}
19
20pub type LocalCompareResult = Result<(), LocalCompareError>;
21
22/// Metadata written to a file used to track state / synchronize across processes.
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub(super) struct EntryMetadata {
25    pub(super) uri: Arc<str>,
26    pub(super) local_last_modified: u64,
27    pub(super) local_size: u64,
28    pub(super) remote_version: FileVersion,
29    /// TTL since last access, in seconds.
30    pub(super) ttl: u64,
31}
32
33impl std::fmt::Display for LocalCompareError {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            Self::LastModifiedMismatch { expected, actual } => write!(
37                f,
38                "last modified time mismatch: expected {expected}, found {actual}"
39            ),
40            Self::SizeMismatch { expected, actual } => {
41                write!(f, "size mismatch: expected {expected}, found {actual}")
42            },
43            Self::DataFileReadError(err) => {
44                write!(f, "failed to read local file metadata: {err}")
45            },
46        }
47    }
48}
49
50impl EntryMetadata {
51    pub(super) fn new(uri: Arc<str>, ttl: u64) -> Self {
52        Self {
53            uri,
54            local_last_modified: 0,
55            local_size: 0,
56            remote_version: FileVersion::Uninitialized,
57            ttl,
58        }
59    }
60
61    pub(super) fn compare_local_state(&self, data_file_path: &Path) -> LocalCompareResult {
62        let metadata = match std::fs::metadata(data_file_path) {
63            Ok(v) => v,
64            Err(e) => return Err(LocalCompareError::DataFileReadError(e)),
65        };
66
67        let local_last_modified = super::utils::last_modified_u64(&metadata);
68        let local_size = metadata.len();
69
70        if local_last_modified != self.local_last_modified {
71            Err(LocalCompareError::LastModifiedMismatch {
72                expected: self.local_last_modified,
73                actual: local_last_modified,
74            })
75        } else if local_size != self.local_size {
76            Err(LocalCompareError::SizeMismatch {
77                expected: self.local_size,
78                actual: local_size,
79            })
80        } else {
81            Ok(())
82        }
83    }
84
85    pub(super) fn try_write<W: std::io::Write>(&self, writer: &mut W) -> serde_json::Result<()> {
86        serde_json::to_writer(writer, self)
87    }
88
89    pub(super) fn try_from_reader<R: std::io::Read>(reader: &mut R) -> serde_json::Result<Self> {
90        serde_json::from_reader(reader)
91    }
92}