Skip to main content

lance_nd/
versions.rs

1//! Read and restore earlier versions of a table.
2//!
3//! Each commit makes a new table version. The files of a version stay until
4//! [`crate::cleanup_old_versions`] removes them.
5
6use std::time::{Duration, SystemTime, UNIX_EPOCH};
7
8use lance::Dataset;
9
10use crate::error::Result;
11use crate::format::check_format;
12
13/// One version of a table.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct TableVersion {
16    /// The version number. The first version is 1.
17    pub version: u64,
18    /// The time of the commit.
19    pub timestamp: SystemTime,
20}
21
22/// The versions of the table that still have their files, oldest first.
23pub async fn versions(dataset: &Dataset) -> Result<Vec<TableVersion>> {
24    check_format(dataset)?;
25    let mut versions: Vec<TableVersion> = dataset
26        .versions()
27        .await?
28        .into_iter()
29        .map(|version| TableVersion {
30            version: version.version,
31            timestamp: UNIX_EPOCH
32                + Duration::from_millis(version.timestamp.timestamp_millis().max(0) as u64),
33        })
34        .collect();
35    versions.sort_by_key(|version| version.version);
36    Ok(versions)
37}
38
39/// The table at `version`, to read. A write to it fails, because it is not
40/// the latest version.
41pub async fn checkout(dataset: &Dataset, version: u64) -> Result<Dataset> {
42    check_format(dataset)?;
43    let old = dataset.checkout_version(version).await?;
44    check_format(&old)?;
45    Ok(old)
46}
47
48/// Make the content of `version` the latest version of the table, in a new
49/// commit. The versions after it stay in the history.
50#[tracing::instrument(skip_all, fields(uri = %dataset.uri(), version = version), err)]
51pub async fn restore(dataset: &mut Dataset, version: u64) -> Result<()> {
52    let mut old = checkout(dataset, version).await?;
53    old.restore().await?;
54    *dataset = old;
55    Ok(())
56}