agave_scheduling_utils/
transaction_ptr.rs1use {
2 agave_scheduler_bindings::{
3 MAX_TRANSACTIONS_PER_MESSAGE, SharableTransactionBatchRegion, SharableTransactionRegion,
4 },
5 agave_transaction_view::transaction_data::TransactionData,
6 core::ptr::NonNull,
7 rts_alloc::Allocator,
8 std::marker::PhantomData,
9};
10
11#[derive(Debug)]
12pub struct TransactionPtr {
13 ptr: NonNull<u8>,
14 count: usize,
15}
16
17impl TransactionData for TransactionPtr {
18 fn data(&self) -> &[u8] {
19 unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.count) }
20 }
21}
22
23impl TransactionData for &TransactionPtr {
24 fn data(&self) -> &[u8] {
25 unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.count) }
26 }
27}
28
29impl TransactionPtr {
30 pub unsafe fn from_raw_parts(ptr: NonNull<u8>, count: usize) -> Self {
42 Self { ptr, count }
43 }
44
45 pub unsafe fn from_sharable_transaction_region(
49 sharable_transaction_region: &SharableTransactionRegion,
50 allocator: &Allocator,
51 ) -> Self {
52 let ptr = unsafe { allocator.ptr_from_offset(sharable_transaction_region.offset) };
54 Self {
55 ptr,
56 count: sharable_transaction_region.length as usize,
57 }
58 }
59
60 pub unsafe fn to_sharable_transaction_region(
66 &self,
67 allocator: &Allocator,
68 ) -> SharableTransactionRegion {
69 let offset = unsafe { allocator.offset(self.ptr) };
73 SharableTransactionRegion {
74 offset,
75 length: self.count as u32,
76 }
77 }
78
79 pub unsafe fn free(self, allocator: &Allocator) {
87 unsafe { allocator.free(self.ptr) }
88 }
89}
90
91pub struct TransactionPtrBatch<'a, M = ()> {
93 tx_ptr: NonNull<SharableTransactionRegion>,
94 meta_ptr: NonNull<M>,
95 num_transactions: usize,
96 allocator: &'a Allocator,
97
98 _meta: PhantomData<M>,
99}
100
101impl<'a, M> TransactionPtrBatch<'a, M> {
102 pub const TRANSACTION_CORE_SIZE: usize = size_of::<SharableTransactionRegion>();
103 pub const TRANSACTION_CORE_END: usize =
104 Self::TRANSACTION_CORE_SIZE * MAX_TRANSACTIONS_PER_MESSAGE;
105
106 pub const TRANSACTION_META_START: usize =
107 Self::TRANSACTION_CORE_END.next_multiple_of(align_of::<M>());
108 pub const TRANSACTION_META_SIZE: usize = size_of::<M>() * MAX_TRANSACTIONS_PER_MESSAGE;
109 pub const TRANSACTION_META_END: usize =
110 Self::TRANSACTION_META_START + Self::TRANSACTION_META_SIZE;
111
112 #[allow(dead_code, reason = "Invariant assertion")]
113 const TRANSACTION_BATCH_SIZE_ASSERT: () = assert!(Self::TRANSACTION_META_END <= 4096);
114
115 pub unsafe fn from_sharable_transaction_batch_region(
122 sharable_transaction_batch_region: &SharableTransactionBatchRegion,
123 allocator: &'a Allocator,
124 ) -> Self {
125 let base = unsafe {
127 allocator.ptr_from_offset(sharable_transaction_batch_region.transactions_offset)
128 };
129 let tx_ptr = base.cast();
130 let meta_ptr = unsafe { base.byte_add(Self::TRANSACTION_META_START).cast() };
134
135 Self {
136 tx_ptr,
137 meta_ptr,
138 num_transactions: usize::from(sharable_transaction_batch_region.num_transactions),
139 allocator,
140
141 _meta: PhantomData,
142 }
143 }
144
145 pub const fn len(&self) -> usize {
147 self.num_transactions
148 }
149
150 pub const fn is_empty(&self) -> bool {
152 self.len() == 0
153 }
154
155 pub fn iter(&'a self) -> impl Iterator<Item = (TransactionPtr, M)> + 'a {
157 (0..self.num_transactions).map(|idx| unsafe {
158 let tx = self.tx_ptr.add(idx);
159 let tx = TransactionPtr::from_sharable_transaction_region(tx.as_ref(), self.allocator);
160 let meta = self.meta_ptr.add(idx).read();
161
162 (tx, meta)
163 })
164 }
165
166 pub unsafe fn free(self) {
177 unsafe { self.allocator.free(self.tx_ptr.cast()) }
178 }
179}