doublecrypt_core/
transaction.rs1use rand::RngCore;
2
3use crate::allocator::SlotAllocator;
4use crate::block_store::BlockStore;
5use crate::codec::{write_encrypted_object, ObjectCodec, PostcardCodec};
6use crate::crypto::CryptoEngine;
7use crate::error::FsResult;
8use crate::model::*;
9
10pub struct TransactionManager {
19 generation: u64,
21 next_is_b: bool,
23}
24
25impl TransactionManager {
26 pub fn new() -> Self {
27 Self {
28 generation: 0,
29 next_is_b: false,
30 }
31 }
32
33 pub fn from_recovered(generation: u64, last_was_b: bool) -> Self {
35 Self {
36 generation,
37 next_is_b: !last_was_b,
38 }
39 }
40
41 pub fn generation(&self) -> u64 {
43 self.generation
44 }
45
46 pub fn commit(
57 &mut self,
58 store: &dyn BlockStore,
59 crypto: &dyn CryptoEngine,
60 codec: &PostcardCodec,
61 allocator: &dyn SlotAllocator,
62 superblock: &Superblock,
63 ) -> FsResult<()> {
64 self.generation += 1;
65
66 let sb_block = allocator.allocate()?;
68
69 write_encrypted_object(
71 store,
72 crypto,
73 codec,
74 sb_block,
75 ObjectKind::Superblock,
76 superblock,
77 )?;
78
79 let sb_bytes = codec.serialize_object(superblock)?;
81 let checksum = blake3::hash(&sb_bytes);
82
83 let root_ptr = RootPointer {
84 generation: self.generation,
85 superblock_ref: ObjectRef::new(sb_block),
86 checksum: *checksum.as_bytes(),
87 };
88
89 let rp_bytes = codec.serialize_object(&root_ptr)?;
91 let block_size = store.block_size();
92 let mut block = vec![0u8; block_size];
93 rand::thread_rng().fill_bytes(&mut block);
94 let len = rp_bytes.len() as u32;
95 block[..4].copy_from_slice(&len.to_le_bytes());
96 block[4..4 + rp_bytes.len()].copy_from_slice(&rp_bytes);
97
98 let slot = if self.next_is_b {
99 BLOCK_ROOT_POINTER_B
100 } else {
101 BLOCK_ROOT_POINTER_A
102 };
103 store.write_block(slot, &block)?;
104
105 self.next_is_b = !self.next_is_b;
106 Ok(())
107 }
108
109 pub fn read_root_pointer(
111 store: &dyn BlockStore,
112 codec: &PostcardCodec,
113 slot: u64,
114 ) -> FsResult<Option<RootPointer>> {
115 let block = store.read_block(slot)?;
116 if block.len() < 4 {
117 return Ok(None);
118 }
119 let len = u32::from_le_bytes([block[0], block[1], block[2], block[3]]) as usize;
120 if len == 0 || 4 + len > block.len() {
121 return Ok(None);
122 }
123 let rp_bytes = &block[4..4 + len];
124 match codec.deserialize_object::<RootPointer>(rp_bytes) {
125 Ok(rp) => Ok(Some(rp)),
126 Err(_) => Ok(None),
127 }
128 }
129
130 pub fn recover_latest(
133 store: &dyn BlockStore,
134 codec: &PostcardCodec,
135 ) -> FsResult<Option<(RootPointer, bool)>> {
136 let rp_a = Self::read_root_pointer(store, codec, BLOCK_ROOT_POINTER_A)?;
137 let rp_b = Self::read_root_pointer(store, codec, BLOCK_ROOT_POINTER_B)?;
138
139 match (rp_a, rp_b) {
140 (Some(a), Some(b)) => {
141 if b.generation >= a.generation {
142 Ok(Some((b, true)))
143 } else {
144 Ok(Some((a, false)))
145 }
146 }
147 (Some(a), None) => Ok(Some((a, false))),
148 (None, Some(b)) => Ok(Some((b, true))),
149 (None, None) => Ok(None),
150 }
151 }
152}