Skip to main content

icydb_core/db/registry/
handle.rs

1use crate::db::{
2    data::DataStore,
3    index::{IndexState, IndexStore},
4    schema::SchemaStore,
5};
6use std::{cell::RefCell, thread::LocalKey};
7
8///
9/// StoreHandle
10///
11/// StoreHandle binds the row, index, and schema stores for one generated schema
12/// `Store` path.
13/// It is the stable access token passed across commit, recovery, executor, and
14/// diagnostics boundaries instead of exposing registry internals directly.
15///
16
17#[derive(Clone, Copy, Debug)]
18pub struct StoreHandle {
19    data: &'static LocalKey<RefCell<DataStore>>,
20    index: &'static LocalKey<RefCell<IndexStore>>,
21    schema: &'static LocalKey<RefCell<SchemaStore>>,
22    allocations: StoreAllocationIdentities,
23}
24
25///
26/// StoreAllocationIdentity
27///
28/// Durable allocation identity for one physical stable-memory role.
29///
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub struct StoreAllocationIdentity {
33    memory_id: u8,
34    stable_key: &'static str,
35}
36
37impl StoreAllocationIdentity {
38    /// Build one stable allocation identity descriptor.
39    #[must_use]
40    pub const fn new(memory_id: u8, stable_key: &'static str) -> Self {
41        Self {
42            memory_id,
43            stable_key,
44        }
45    }
46
47    /// Stable-memory manager ID.
48    #[must_use]
49    pub const fn memory_id(self) -> u8 {
50        self.memory_id
51    }
52
53    /// Durable stable-memory key.
54    #[must_use]
55    pub const fn stable_key(self) -> &'static str {
56        self.stable_key
57    }
58}
59
60///
61/// StoreAllocationIdentities
62///
63/// Durable allocation identities for one logical store's data, index, and
64/// schema memories.
65///
66
67#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
68pub struct StoreAllocationIdentities {
69    data: Option<StoreAllocationIdentity>,
70    index: Option<StoreAllocationIdentity>,
71    schema: Option<StoreAllocationIdentity>,
72}
73
74impl StoreAllocationIdentities {
75    /// Build an absent allocation identity bundle.
76    #[must_use]
77    pub const fn absent() -> Self {
78        Self {
79            data: None,
80            index: None,
81            schema: None,
82        }
83    }
84
85    /// Build one allocation identity bundle.
86    #[must_use]
87    pub const fn new(
88        data: StoreAllocationIdentity,
89        index: StoreAllocationIdentity,
90        schema: StoreAllocationIdentity,
91    ) -> Self {
92        Self {
93            data: Some(data),
94            index: Some(index),
95            schema: Some(schema),
96        }
97    }
98
99    /// Return data-memory allocation identity.
100    #[must_use]
101    pub const fn data(self) -> Option<StoreAllocationIdentity> {
102        self.data
103    }
104
105    /// Return index-memory allocation identity.
106    #[must_use]
107    pub const fn index(self) -> Option<StoreAllocationIdentity> {
108        self.index
109    }
110
111    /// Return schema-memory allocation identity.
112    #[must_use]
113    pub const fn schema(self) -> Option<StoreAllocationIdentity> {
114        self.schema
115    }
116}
117
118impl StoreHandle {
119    /// Build a store handle from thread-local row/index/schema stores.
120    #[must_use]
121    pub const fn new(
122        data: &'static LocalKey<RefCell<DataStore>>,
123        index: &'static LocalKey<RefCell<IndexStore>>,
124        schema: &'static LocalKey<RefCell<SchemaStore>>,
125    ) -> Self {
126        Self::new_with_allocations(data, index, schema, StoreAllocationIdentities::absent())
127    }
128
129    /// Build a store handle with stable allocation identities.
130    #[must_use]
131    pub const fn new_with_allocations(
132        data: &'static LocalKey<RefCell<DataStore>>,
133        index: &'static LocalKey<RefCell<IndexStore>>,
134        schema: &'static LocalKey<RefCell<SchemaStore>>,
135        allocations: StoreAllocationIdentities,
136    ) -> Self {
137        Self {
138            data,
139            index,
140            schema,
141            allocations,
142        }
143    }
144
145    /// Borrow the row store immutably.
146    pub fn with_data<R>(&self, f: impl FnOnce(&DataStore) -> R) -> R {
147        #[cfg(feature = "diagnostics")]
148        {
149            crate::db::physical_access::measure_physical_access_operation(|| {
150                self.data.with_borrow(f)
151            })
152        }
153
154        #[cfg(not(feature = "diagnostics"))]
155        {
156            self.data.with_borrow(f)
157        }
158    }
159
160    /// Borrow the row store mutably.
161    pub fn with_data_mut<R>(&self, f: impl FnOnce(&mut DataStore) -> R) -> R {
162        self.data.with_borrow_mut(f)
163    }
164
165    /// Borrow the index store immutably.
166    pub fn with_index<R>(&self, f: impl FnOnce(&IndexStore) -> R) -> R {
167        #[cfg(feature = "diagnostics")]
168        {
169            crate::db::physical_access::measure_physical_access_operation(|| {
170                self.index.with_borrow(f)
171            })
172        }
173
174        #[cfg(not(feature = "diagnostics"))]
175        {
176            self.index.with_borrow(f)
177        }
178    }
179
180    /// Borrow the index store mutably.
181    pub fn with_index_mut<R>(&self, f: impl FnOnce(&mut IndexStore) -> R) -> R {
182        self.index.with_borrow_mut(f)
183    }
184
185    /// Borrow the schema store immutably.
186    pub fn with_schema<R>(&self, f: impl FnOnce(&SchemaStore) -> R) -> R {
187        self.schema.with_borrow(f)
188    }
189
190    /// Borrow the schema store mutably.
191    pub fn with_schema_mut<R>(&self, f: impl FnOnce(&mut SchemaStore) -> R) -> R {
192        self.schema.with_borrow_mut(f)
193    }
194
195    /// Return the explicit lifecycle state of the bound index store.
196    #[must_use]
197    pub(in crate::db) fn index_state(&self) -> IndexState {
198        self.with_index(IndexStore::state)
199    }
200
201    /// Mark the bound index store as Building.
202    pub(in crate::db) fn mark_index_building(&self) {
203        self.with_index_mut(IndexStore::mark_building);
204    }
205
206    /// Mark the bound index store as Ready.
207    pub(in crate::db) fn mark_index_ready(&self) {
208        self.with_index_mut(IndexStore::mark_ready);
209    }
210
211    /// Return the raw row-store accessor.
212    #[must_use]
213    pub const fn data_store(&self) -> &'static LocalKey<RefCell<DataStore>> {
214        self.data
215    }
216
217    /// Return the raw index-store accessor.
218    #[must_use]
219    pub const fn index_store(&self) -> &'static LocalKey<RefCell<IndexStore>> {
220        self.index
221    }
222
223    /// Return the raw schema-store accessor.
224    #[must_use]
225    pub const fn schema_store(&self) -> &'static LocalKey<RefCell<SchemaStore>> {
226        self.schema
227    }
228
229    /// Return the data-memory allocation identity when generated wiring
230    /// supplied it.
231    #[must_use]
232    pub const fn data_allocation(&self) -> Option<StoreAllocationIdentity> {
233        self.allocations.data()
234    }
235
236    /// Return the index-memory allocation identity when generated wiring
237    /// supplied it.
238    #[must_use]
239    pub const fn index_allocation(&self) -> Option<StoreAllocationIdentity> {
240        self.allocations.index()
241    }
242
243    /// Return the schema-memory allocation identity when generated wiring
244    /// supplied it.
245    #[must_use]
246    pub const fn schema_allocation(&self) -> Option<StoreAllocationIdentity> {
247        self.allocations.schema()
248    }
249}