Skip to main content

storage/
traits.rs

1use std::sync::Arc;
2
3use async_trait::async_trait;
4use common::{NamespaceId, Result, Vector, VectorId};
5
6/// Index types that can be persisted
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum IndexType {
9    /// HNSW graph index
10    Hnsw,
11    /// Product Quantization index
12    Pq,
13    /// IVF (Inverted File) index
14    Ivf,
15    /// SPFresh index
16    SpFresh,
17    /// Full-text inverted index
18    FullText,
19}
20
21impl IndexType {
22    pub fn as_str(&self) -> &'static str {
23        match self {
24            IndexType::Hnsw => "hnsw",
25            IndexType::Pq => "pq",
26            IndexType::Ivf => "ivf",
27            IndexType::SpFresh => "spfresh",
28            IndexType::FullText => "fulltext",
29        }
30    }
31}
32
33/// Storage trait for persisting index data
34#[async_trait]
35pub trait IndexStorage: Send + Sync {
36    /// Save index data for a namespace
37    async fn save_index(
38        &self,
39        namespace: &NamespaceId,
40        index_type: IndexType,
41        data: Vec<u8>,
42    ) -> Result<()>;
43
44    /// Load index data for a namespace
45    async fn load_index(
46        &self,
47        namespace: &NamespaceId,
48        index_type: IndexType,
49    ) -> Result<Option<Vec<u8>>>;
50
51    /// Delete index data for a namespace
52    async fn delete_index(&self, namespace: &NamespaceId, index_type: IndexType) -> Result<bool>;
53
54    /// Check if index exists for a namespace
55    async fn index_exists(&self, namespace: &NamespaceId, index_type: IndexType) -> Result<bool>;
56
57    /// List all indexes for a namespace
58    async fn list_indexes(&self, namespace: &NamespaceId) -> Result<Vec<IndexType>>;
59}
60
61/// Blanket implementation for Arc<T>
62#[async_trait]
63impl<T: IndexStorage + ?Sized> IndexStorage for Arc<T> {
64    async fn save_index(
65        &self,
66        namespace: &NamespaceId,
67        index_type: IndexType,
68        data: Vec<u8>,
69    ) -> Result<()> {
70        (**self).save_index(namespace, index_type, data).await
71    }
72
73    async fn load_index(
74        &self,
75        namespace: &NamespaceId,
76        index_type: IndexType,
77    ) -> Result<Option<Vec<u8>>> {
78        (**self).load_index(namespace, index_type).await
79    }
80
81    async fn delete_index(&self, namespace: &NamespaceId, index_type: IndexType) -> Result<bool> {
82        (**self).delete_index(namespace, index_type).await
83    }
84
85    async fn index_exists(&self, namespace: &NamespaceId, index_type: IndexType) -> Result<bool> {
86        (**self).index_exists(namespace, index_type).await
87    }
88
89    async fn list_indexes(&self, namespace: &NamespaceId) -> Result<Vec<IndexType>> {
90        (**self).list_indexes(namespace).await
91    }
92}
93
94/// Core storage abstraction - implementations can be in-memory, S3, etc.
95#[async_trait]
96pub trait VectorStorage: Send + Sync {
97    /// Store or update vectors in a namespace
98    async fn upsert(&self, namespace: &NamespaceId, vectors: Vec<Vector>) -> Result<usize>;
99
100    /// Get vectors by IDs
101    async fn get(&self, namespace: &NamespaceId, ids: &[VectorId]) -> Result<Vec<Vector>>;
102
103    /// Get all vectors in a namespace (for brute-force search)
104    async fn get_all(&self, namespace: &NamespaceId) -> Result<Vec<Vector>>;
105
106    /// Delete vectors by IDs
107    async fn delete(&self, namespace: &NamespaceId, ids: &[VectorId]) -> Result<usize>;
108
109    /// Check if namespace exists
110    async fn namespace_exists(&self, namespace: &NamespaceId) -> Result<bool>;
111
112    /// Create namespace if it doesn't exist
113    async fn ensure_namespace(&self, namespace: &NamespaceId) -> Result<()>;
114
115    /// Get vector count in namespace
116    async fn count(&self, namespace: &NamespaceId) -> Result<usize>;
117
118    /// Get vector dimension for namespace (None if empty)
119    async fn dimension(&self, namespace: &NamespaceId) -> Result<Option<usize>>;
120
121    /// List all namespaces
122    async fn list_namespaces(&self) -> Result<Vec<NamespaceId>>;
123
124    /// Delete a namespace and all its vectors
125    async fn delete_namespace(&self, namespace: &NamespaceId) -> Result<bool>;
126
127    /// Clean up expired vectors in a namespace
128    /// Returns the number of vectors removed
129    async fn cleanup_expired(&self, namespace: &NamespaceId) -> Result<usize>;
130
131    /// Clean up expired vectors in all namespaces
132    /// Returns total number of vectors removed
133    async fn cleanup_all_expired(&self) -> Result<usize>;
134}
135
136/// Blanket implementation for Arc<T> to enable dynamic dispatch
137#[async_trait]
138impl<T: VectorStorage + ?Sized> VectorStorage for Arc<T> {
139    async fn upsert(&self, namespace: &NamespaceId, vectors: Vec<Vector>) -> Result<usize> {
140        (**self).upsert(namespace, vectors).await
141    }
142
143    async fn get(&self, namespace: &NamespaceId, ids: &[VectorId]) -> Result<Vec<Vector>> {
144        (**self).get(namespace, ids).await
145    }
146
147    async fn get_all(&self, namespace: &NamespaceId) -> Result<Vec<Vector>> {
148        (**self).get_all(namespace).await
149    }
150
151    async fn delete(&self, namespace: &NamespaceId, ids: &[VectorId]) -> Result<usize> {
152        (**self).delete(namespace, ids).await
153    }
154
155    async fn namespace_exists(&self, namespace: &NamespaceId) -> Result<bool> {
156        (**self).namespace_exists(namespace).await
157    }
158
159    async fn ensure_namespace(&self, namespace: &NamespaceId) -> Result<()> {
160        (**self).ensure_namespace(namespace).await
161    }
162
163    async fn count(&self, namespace: &NamespaceId) -> Result<usize> {
164        (**self).count(namespace).await
165    }
166
167    async fn dimension(&self, namespace: &NamespaceId) -> Result<Option<usize>> {
168        (**self).dimension(namespace).await
169    }
170
171    async fn list_namespaces(&self) -> Result<Vec<NamespaceId>> {
172        (**self).list_namespaces().await
173    }
174
175    async fn delete_namespace(&self, namespace: &NamespaceId) -> Result<bool> {
176        (**self).delete_namespace(namespace).await
177    }
178
179    async fn cleanup_expired(&self, namespace: &NamespaceId) -> Result<usize> {
180        (**self).cleanup_expired(namespace).await
181    }
182
183    async fn cleanup_all_expired(&self) -> Result<usize> {
184        (**self).cleanup_all_expired().await
185    }
186}