Skip to main content

lance/session/
index_caches.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Caches for Lance indices. They are organized in a hierarchical manner to
5//! avoid collisions.
6//!
7//!  GlobalIndexCache
8//!     │
9//!     ├─► DSIndexCache (prefixed by dataset URI)
10//!     │    │
11//!     └────┴──► Index-specific cache (prefixed by index UUID and FRI UUID)
12
13use std::{borrow::Cow, ops::Deref, sync::Arc};
14
15use deepsize::{Context, DeepSizeOf};
16use lance_core::cache::{CacheKey, LanceCache};
17use lance_index::frag_reuse::FragReuseIndex;
18use lance_table::format::IndexMetadata;
19use uuid::Uuid;
20
21/// A type-safe wrapper around a LanceCache that enforces namespaces for index data.
22pub struct GlobalIndexCache(pub(super) LanceCache);
23
24impl GlobalIndexCache {
25    pub fn for_dataset(&self, uri: &str) -> DSIndexCache {
26        // Create a sub-cache for the dataset by adding the URI as a key prefix.
27        // This prevents collisions between different datasets.
28        DSIndexCache(self.0.with_key_prefix(uri))
29    }
30}
31
32impl Clone for GlobalIndexCache {
33    fn clone(&self) -> Self {
34        Self(self.0.clone())
35    }
36}
37
38impl Deref for GlobalIndexCache {
39    type Target = LanceCache;
40
41    fn deref(&self) -> &Self::Target {
42        &self.0
43    }
44}
45
46impl DeepSizeOf for GlobalIndexCache {
47    fn deep_size_of_children(&self, context: &mut Context) -> usize {
48        self.0.deep_size_of_children(context)
49    }
50}
51
52/// A type-safe wrapper around a LanceCache that enforces namespaces and keys
53/// for dataset-specific index data.
54pub struct DSIndexCache(pub(crate) LanceCache);
55
56impl Deref for DSIndexCache {
57    type Target = LanceCache;
58
59    fn deref(&self) -> &Self::Target {
60        &self.0
61    }
62}
63
64impl DSIndexCache {
65    /// Create an index-specific cache with the given UUID prefix.
66    pub fn for_index(&self, uuid: &str, fri_uuid: Option<&Uuid>) -> LanceCache {
67        if let Some(fri_uuid) = fri_uuid {
68            // If a FRI UUID is provided, use it to create a more specific cache key.
69            let cache_key = format!("{}-{}", uuid, fri_uuid);
70            self.0.with_key_prefix(&cache_key)
71        } else {
72            // Otherwise, just use the index UUID as the key prefix.
73            self.0.with_key_prefix(uuid)
74        }
75    }
76}
77
78// Cache key types for type-safe cache access
79
80#[derive(Debug)]
81pub struct FragReuseIndexKey<'a> {
82    pub uuid: &'a str,
83}
84
85impl CacheKey for FragReuseIndexKey<'_> {
86    type ValueType = FragReuseIndex;
87
88    fn key(&self) -> Cow<'_, str> {
89        Cow::Owned(format!("frag_reuse/{}", self.uuid))
90    }
91
92    fn type_name() -> &'static str {
93        "FragReuseIndex"
94    }
95}
96
97#[derive(Debug)]
98pub struct IndexMetadataKey {
99    pub version: u64,
100}
101
102impl CacheKey for IndexMetadataKey {
103    type ValueType = Vec<IndexMetadata>;
104
105    fn key(&self) -> Cow<'_, str> {
106        Cow::Owned(self.version.to_string())
107    }
108
109    fn type_name() -> &'static str {
110        "Vec<IndexMetadata>"
111    }
112
113    fn codec() -> Option<lance_core::cache::CacheCodec> {
114        Some(lance_table::format::index_metadata_codec())
115    }
116}
117
118pub struct ProstAny(pub Arc<prost_types::Any>);
119
120impl DeepSizeOf for ProstAny {
121    fn deep_size_of_children(&self, context: &mut Context) -> usize {
122        self.0.type_url.deep_size_of_children(context) + self.0.value.deep_size_of_children(context)
123    }
124}
125
126/// Cache key for scalar index details
127///
128/// Typically we don't use the cache for scalar index details because they are stored
129/// in the manifest and readily available.  However, old versions of Lance didn't store
130/// details in the manifest, and we have to perform an expensive inference process to determine
131/// what they are.  These we cache.
132#[derive(Debug)]
133pub struct ScalarIndexDetailsKey<'a> {
134    pub uuid: &'a str,
135}
136
137impl CacheKey for ScalarIndexDetailsKey<'_> {
138    type ValueType = ProstAny;
139
140    fn key(&self) -> Cow<'_, str> {
141        Cow::Owned(format!("type/{}", self.uuid))
142    }
143
144    fn type_name() -> &'static str {
145        "ScalarIndexDetails"
146    }
147}