Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_o3db_sync/src/dist/record.rs

2.8 KiB, 28 runs

created by r1870400018:11390, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Record addressing for distributed Ozone.
2//!
3//! A distributed-mode record is identified by the pair `(table, key)`. The
4//! caller hashes this pair (or just the key, if the table is partitioned by
5//! name elsewhere) into a 256-bit [`RecordId`] for OAM placement. This crate
6//! does not prescribe the hash function -- the caller hands in a [`RecordId`]
7//! that has already been computed, in the same way the underlying primitive
8//! crates take pre-computed [`NodeId`]s.
9//!
10//! [`NodeId`]: crate::kademlia::id::NodeId
11//!
12//! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\
13//! Anthropic Claude
14
15use oxedyne_fe2o3_core::prelude::*;
16use crate::kademlia::id::{
17 ID_LEN,
18 NodeId,
19};
20
21
22/// A 256-bit record identifier, shared with the Kademlia / OAM identifier
23/// space. This is the caller's pre-computed hash of the record's canonical
24/// form -- typically `(table_name, key)` serialised and run through a
25/// cryptographic hash such as SHA-3 or BLAKE3.
26///
27/// A [`RecordId`] is reinterpreted as a [`NodeId`] for placement decisions so
28/// that XOR distance against a peer identifier is well-defined.
29#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
30pub struct RecordId(pub [u8; ID_LEN]);
31
32impl RecordId {
33 pub const fn from_bytes(bytes: [u8; ID_LEN]) -> Self {
34 Self(bytes)
35 }
36
37 /// The slice must be exactly [`ID_LEN`] bytes.
38 pub fn from_slice(bytes: &[u8]) -> Outcome<Self> {
39 if bytes.len() != ID_LEN {
40 return Err(err!(
41 "RecordId requires exactly {} bytes, got {}.",
42 ID_LEN, bytes.len();
43 Invalid, Input, Size));
44 }
45 let mut arr = [0u8; ID_LEN];
46 arr.copy_from_slice(bytes);
47 Ok(Self(arr))
48 }
49
50 pub fn as_node_id(&self) -> NodeId {
51 NodeId::from_bytes(self.0)
52 }
53
54 pub fn as_bytes(&self) -> &[u8; ID_LEN] {
55 &self.0
56 }
57}
58
59impl From<NodeId> for RecordId {
60 fn from(n: NodeId) -> Self {
61 Self(*n.as_bytes())
62 }
63}
64
65impl From<RecordId> for NodeId {
66 fn from(r: RecordId) -> Self {
67 r.as_node_id()
68 }
69}
70
71
72/// A distributed-mode record: the identifier, the application-opaque value,
73/// and the table it belongs to. Values are held as byte vectors -- the
74/// application is responsible for serialisation.
75#[derive(Clone, Debug, Eq, PartialEq)]
76pub struct Record {
77 pub id: RecordId,
78 pub table: String, // matched against a TableConfig
79 pub value: Vec<u8>,
80}
81
82impl Record {
83 pub fn new<S: Into<String>>(
84 id: RecordId,
85 table: S,
86 value: Vec<u8>,
87 )
88 -> Self
89 {
90 Self { id, table: table.into(), value }
91 }
92}
93
94/// A summary of a [`Record`] suitable for IBLT anti-entropy sketches and
95/// replication decisions that do not need to carry the full value payload.
96#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub struct RecordDigest {
98 pub id: RecordId,
99 // Caller-supplied, so distributed Ozone is tied to no particular hash.
100 pub content: [u8; 32], // detects divergent copies at the same id
101}