tiger_pkg/manager/
lookup_cache.rs1use 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}