1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};
use super::address::{Address, RevisionId, SpaceId};
use super::checksum::Checksum;
use super::hilbert_key::CachedHilbertKey;
/// Stable identifier for a block on disk.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)]
pub struct BlockId(pub u64);
/// A single record: a spatial address, a revision, raw serialized data,
/// and a tombstone flag (true = this record has been logically deleted).
/// Records are immutable once written — updates append new revisions.
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct Record {
pub address: Address,
pub revision: RevisionId,
/// Serialized payload (bincode-encoded). Empty when `tombstone` is true.
pub data: Vec<u8>,
/// Marks this revision as a logical deletion.
pub tombstone: bool,
/// Hilbert key computed once at insert; unset means recompute from coordinates.
#[serde(default)]
pub hilbert_key: CachedHilbertKey,
}
/// An immutable, sorted collection of records sharing a contiguous Hilbert
/// key range. Once written, a block is never mutated — compaction produces
/// replacement blocks.
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct Block {
pub id: BlockId,
pub space: SpaceId,
/// Records sorted by (address.point, revision) ascending.
pub records: Vec<Record>,
/// Revision range covered — used to skip blocks during history queries.
pub min_revision: RevisionId,
pub max_revision: RevisionId,
/// Blake3 checksum of the serialized records for integrity verification.
pub checksum: Checksum,
}
impl Block {
/// Returns true if this block contains any live (non-tombstoned) records
/// at or before the given revision.
pub fn has_live_records_at(&self, rev: RevisionId) -> bool {
self.records
.iter()
.any(|r| r.revision <= rev && !r.tombstone)
}
/// Returns the latest record at the given address at or before `rev`,
/// if one exists and is not a tombstone.
pub fn get_at(&self, address: &Address, rev: RevisionId) -> Option<&Record> {
self.records
.iter()
.filter(|r| &r.address == address && r.revision <= rev)
.max_by_key(|r| r.revision)
.filter(|r| !r.tombstone)
}
}