tiger_pkg/manager/
lookup_cache.rs

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