Skip to main content

reifydb_transaction/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3#![cfg_attr(not(debug_assertions), deny(clippy::disallowed_methods))]
4#![cfg_attr(debug_assertions, warn(clippy::disallowed_methods))]
5#![cfg_attr(not(debug_assertions), deny(warnings))]
6#![allow(clippy::tabs_in_doc_comments)]
7
8use std::{
9	fmt,
10	fmt::{Display, Formatter},
11	ops::Deref,
12};
13
14use reifydb_core::{
15	interface::version::{ComponentType, HasVersion, SystemVersion},
16	return_internal_error,
17};
18use reifydb_runtime::context::{clock::Clock, rng::Rng};
19use reifydb_type::{error::Error, value::uuid::Uuid7};
20use uuid::{Builder, Uuid};
21
22pub mod change;
23pub mod change_accumulator;
24pub mod delta;
25pub mod error;
26pub mod interceptor;
27pub mod multi;
28pub mod single;
29pub mod transaction;
30
31/// A unique identifier for a transaction using UUIDv7 for time-ordered
32/// uniqueness
33#[repr(transparent)]
34#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
35pub struct TransactionId(pub(crate) Uuid7);
36
37impl Deref for TransactionId {
38	type Target = Uuid7;
39
40	fn deref(&self) -> &Self::Target {
41		&self.0
42	}
43}
44
45impl TransactionId {
46	/// Generate a new transaction ID using the infrastructure RNG stream.
47	///
48	/// Uses `rng.infra_bytes_10()` instead of `rng.bytes_10()` so that
49	/// transaction ID generation does not consume from the primary RNG.
50	/// This ensures deterministic test output across runners that create
51	/// different numbers of internal transactions (e.g. gRPC vs embedded).
52	pub fn generate(clock: &Clock, rng: &Rng) -> Self {
53		let millis = clock.now_millis();
54		let random_bytes = rng.infra_bytes_10();
55		Self(Uuid7(Builder::from_unix_timestamp_millis(millis, &random_bytes).into_uuid()))
56	}
57}
58
59impl TryFrom<&[u8]> for TransactionId {
60	type Error = Error;
61
62	fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
63		if bytes.len() != 16 {
64			return_internal_error!("Invalid transaction ID length: expected 16 bytes, got {}", bytes.len());
65		}
66		let mut uuid_bytes = [0u8; 16];
67		uuid_bytes.copy_from_slice(bytes);
68		let uuid = Uuid::from_bytes(uuid_bytes);
69		Ok(Self(Uuid7::from(uuid)))
70	}
71}
72
73impl Display for TransactionId {
74	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
75		write!(f, "{}", self.0)
76	}
77}
78
79pub struct TransactionVersion;
80
81impl HasVersion for TransactionVersion {
82	fn version(&self) -> SystemVersion {
83		SystemVersion {
84			name: env!("CARGO_PKG_NAME")
85				.strip_prefix("reifydb-")
86				.unwrap_or(env!("CARGO_PKG_NAME"))
87				.to_string(),
88			version: env!("CARGO_PKG_VERSION").to_string(),
89			description: "Transaction management and concurrency control module".to_string(),
90			r#type: ComponentType::Module,
91		}
92	}
93}