Skip to main content

reifydb_transaction/single/
read.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::mem;
5
6use reifydb_core::interface::store::{SingleVersionContains, SingleVersionGet, SingleVersionValues};
7use reifydb_runtime::sync::rwlock::{RwLock, RwLockReadGuard};
8use reifydb_type::{Result, util::hex};
9
10use super::*;
11use crate::error::TransactionError;
12
13/// Holds both the Arc and the guard to keep the lock alive
14#[allow(dead_code)]
15pub struct KeyReadLock {
16	pub(super) _arc: Arc<RwLock<()>>,
17	pub(super) _guard: RwLockReadGuard<'static, ()>,
18}
19
20impl KeyReadLock {
21	/// Creates a new KeyReadLock by taking a read guard and storing it with the Arc.
22	///
23	/// # Safety
24	/// This function uses unsafe code to extend the lifetime of the guard to 'static.
25	/// This is safe because:
26	/// 1. The guard borrows from the RwLock inside the Arc
27	/// 2. We store the Arc in this struct, keeping the RwLock alive
28	/// 3. The guard will be dropped before or with the Arc (due to field order)
29	/// 4. As long as this struct exists, the Arc exists, so the RwLock exists
30	pub(super) fn new(arc: Arc<RwLock<()>>) -> Self {
31		// Take the guard while we still have a reference to arc
32		let guard = arc.read();
33
34		// SAFETY: We're extending the guard's lifetime to 'static.
35		// This is sound because we're also storing the Arc, which keeps
36		// the underlying RwLock alive for as long as this struct exists.
37		let guard = unsafe { mem::transmute::<RwLockReadGuard<'_, ()>, RwLockReadGuard<'static, ()>>(guard) };
38
39		Self {
40			_arc: arc,
41			_guard: guard,
42		}
43	}
44}
45
46pub struct SingleReadTransaction<'a> {
47	pub(super) inner: &'a SingleTransactionInner,
48	pub(super) keys: Vec<EncodedKey>,
49	pub(super) _key_locks: Vec<KeyReadLock>,
50}
51
52impl<'a> SingleReadTransaction<'a> {
53	#[inline]
54	fn check_key_allowed(&self, key: &EncodedKey) -> Result<()> {
55		if self.keys.iter().any(|k| k == key) {
56			Ok(())
57		} else {
58			Err(TransactionError::KeyOutOfScope {
59				key: hex::encode(&key),
60			}
61			.into())
62		}
63	}
64
65	pub fn get(&mut self, key: &EncodedKey) -> Result<Option<SingleVersionValues>> {
66		self.check_key_allowed(key)?;
67		let store = self.inner.store.read().clone();
68		SingleVersionGet::get(&store, key)
69	}
70
71	pub fn contains_key(&mut self, key: &EncodedKey) -> Result<bool> {
72		self.check_key_allowed(key)?;
73		let store = self.inner.store.read().clone();
74		SingleVersionContains::contains(&store, key)
75	}
76}