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