tiger_pkg/manager/
lookup_cache.rs

1use itertools::MultiUnzip;
2use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
3use tracing::{error, info};
4
5use super::{PackageManager, TagLookupIndex};
6use crate::{manager::HashTableEntryShort, TagHash64, Version};
7
8impl PackageManager {
9    const LOOKUP_CACHE_MAGIC: [u8; 4] = *b"TLI0";
10
11    #[cfg(feature = "ignore_lookup_cache")]
12    pub(super) fn read_lookup_cache(&self) -> Option<TagLookupIndex> {
13        info!("Not loading tag cache: ignore_lookup_cache feature flag is set");
14        None
15    }
16
17    #[cfg(feature = "ignore_lookup_cache")]
18    pub(super) fn write_lookup_cache(&self) -> anyhow::Result<()> {
19        Ok(())
20    }
21
22    #[cfg(not(feature = "ignore_lookup_cache"))]
23    pub(super) fn read_lookup_cache(&self) -> Option<TagLookupIndex> {
24        use std::io::Read;
25
26        use crate::manager::path_cache::exe_relative_path;
27
28        let mut file = std::fs::File::open(exe_relative_path(&format!(
29            "lookup_cache_{}.bin",
30            self.cache_key()
31        )))
32        .ok()?;
33
34        let mut cache_data = Vec::new();
35        file.read_to_end(&mut cache_data).ok()?;
36        if cache_data[..4] != Self::LOOKUP_CACHE_MAGIC {
37            error!("Invalid lookup cache magic");
38            return None;
39        }
40
41        info!("Loading index cache");
42
43        let cache: Option<TagLookupIndex> =
44            bincode::decode_from_slice(&cache_data[4..], bincode::config::legacy())
45                .map(|(v, _)| v)
46                .ok();
47
48        cache
49    }
50
51    #[cfg(not(feature = "ignore_lookup_cache"))]
52    pub(super) fn write_lookup_cache(&self) -> anyhow::Result<()> {
53        use super::path_cache::exe_relative_path;
54
55        let mut data = Vec::new();
56        data.extend_from_slice(&Self::LOOKUP_CACHE_MAGIC);
57        data.extend_from_slice(&bincode::encode_to_vec(
58            &self.lookup,
59            bincode::config::legacy(),
60        )?);
61
62        Ok(std::fs::write(
63            exe_relative_path(&format!("lookup_cache_{}.bin", self.cache_key())),
64            data,
65        )?)
66    }
67
68    pub fn build_lookup_tables(&mut self) {
69        let start = std::time::Instant::now();
70        let tables: Vec<_> = self
71            .package_paths
72            .par_iter()
73            .filter_map(|(_, p)| {
74                let pkg = match self.version.open(&p.path) {
75                    Ok(package) => package,
76                    Err(e) => {
77                        error!("Failed to open package '{}': {e}", p.filename);
78                        return None;
79                    }
80                };
81                let entries = (pkg.pkg_id(), pkg.entries().to_vec());
82
83                let collect = pkg
84                    .hash64_table()
85                    .iter()
86                    .map(|h| {
87                        (
88                            h.hash64,
89                            HashTableEntryShort {
90                                hash32: h.hash32,
91                                reference: h.reference,
92                            },
93                        )
94                    })
95                    .collect::<Vec<(u64, HashTableEntryShort)>>();
96                let hashes = collect;
97
98                let named_tags = pkg.named_tags();
99
100                Some((entries, hashes, named_tags))
101            })
102            .collect();
103
104        let (entries, hashes, named_tags): (_, Vec<_>, Vec<_>) = tables.into_iter().multiunzip();
105
106        self.lookup = TagLookupIndex {
107            tag32_entries_by_pkg: entries,
108            tag32_to_tag64: hashes
109                .iter()
110                .flatten()
111                .map(|(h64, entry)| (entry.hash32, TagHash64(*h64)))
112                .collect(),
113            tag64_entries: hashes.into_iter().flatten().collect(),
114            named_tags: named_tags.into_iter().flatten().collect(),
115        };
116
117        info!(
118            "Built lookup table for {} packages in {:?}",
119            self.lookup.tag32_entries_by_pkg.len(),
120            start.elapsed()
121        );
122    }
123}