ab_client_database/storage_backend.rs
1use futures::channel::oneshot;
2use std::mem::MaybeUninit;
3use std::{fmt, io, mem};
4
5/// A wrapper data structure with 4096 bytes alignment, which is the most common alignment for
6/// direct I/O operations.
7#[derive(Debug, Copy, Clone)]
8#[repr(C, align(4096))]
9pub struct AlignedPage([u8; AlignedPage::SIZE]);
10
11const _: () = {
12 assert!(align_of::<AlignedPage>() == AlignedPage::SIZE);
13};
14
15impl Default for AlignedPage {
16 #[inline(always)]
17 fn default() -> Self {
18 Self([0; AlignedPage::SIZE])
19 }
20}
21
22impl AlignedPage {
23 /// 4096 is as a relatively safe size due to sector size on SSDs commonly being 512 or 4096
24 /// bytes
25 pub const SIZE: usize = 4096;
26
27 /// Convert an exclusive slice to an uninitialized version
28 pub fn as_uninit_slice_mut(value: &mut [Self]) -> &mut [MaybeUninit<Self>] {
29 // SAFETY: Same layout
30 unsafe { mem::transmute(value) }
31 }
32
33 /// Convenient conversion from slice to underlying representation for efficiency purposes
34 #[inline(always)]
35 pub fn slice_to_repr(value: &[Self]) -> &[[u8; AlignedPage::SIZE]] {
36 // SAFETY: `AlignedPage` is `#[repr(C)]` and guaranteed to have the same memory layout
37 unsafe { mem::transmute(value) }
38 }
39
40 /// Convenient conversion from slice to underlying representation for efficiency purposes
41 #[inline(always)]
42 pub fn uninit_slice_to_repr(
43 value: &[MaybeUninit<Self>],
44 ) -> &[MaybeUninit<[u8; AlignedPage::SIZE]>] {
45 // SAFETY: `AlignedPage` is `#[repr(C)]` and guaranteed to have the same memory layout
46 unsafe { mem::transmute(value) }
47 }
48
49 /// Convenient conversion from a slice of underlying representation for efficiency purposes.
50 ///
51 /// Returns `None` if not correctly aligned.
52 #[inline]
53 pub fn try_slice_from_repr(value: &[[u8; AlignedPage::SIZE]]) -> Option<&[Self]> {
54 // SAFETY: All bit patterns are valid
55 let (before, slice, after) = unsafe { value.align_to::<Self>() };
56
57 if before.is_empty() && after.is_empty() {
58 Some(slice)
59 } else {
60 None
61 }
62 }
63
64 /// Convenient conversion from a slice of underlying representation for efficiency purposes.
65 ///
66 /// Returns `None` if not correctly aligned.
67 #[inline]
68 pub fn try_uninit_slice_from_repr(
69 value: &[MaybeUninit<[u8; AlignedPage::SIZE]>],
70 ) -> Option<&[MaybeUninit<Self>]> {
71 // SAFETY: All bit patterns are valid
72 let (before, slice, after) = unsafe { value.align_to::<MaybeUninit<Self>>() };
73
74 if before.is_empty() && after.is_empty() {
75 Some(slice)
76 } else {
77 None
78 }
79 }
80
81 /// Convenient conversion from mutable slice to underlying representation for efficiency
82 /// purposes
83 #[inline(always)]
84 pub fn slice_mut_to_repr(slice: &mut [Self]) -> &mut [[u8; AlignedPage::SIZE]] {
85 // SAFETY: `AlignedSectorSize` is `#[repr(C)]` and its alignment is larger than inner value
86 unsafe { mem::transmute(slice) }
87 }
88
89 /// Convenient conversion from mutable slice to underlying representation for efficiency
90 /// purposes
91 #[inline(always)]
92 pub fn uninit_slice_mut_to_repr(
93 slice: &mut [MaybeUninit<Self>],
94 ) -> &mut [MaybeUninit<[u8; AlignedPage::SIZE]>] {
95 // SAFETY: `AlignedSectorSize` is `#[repr(C)]` and its alignment is larger than inner value
96 unsafe { mem::transmute(slice) }
97 }
98
99 /// Convenient conversion from a slice of underlying representation for efficiency purposes.
100 ///
101 /// Returns `None` if not correctly aligned.
102 #[inline]
103 pub fn try_slice_mut_from_repr(value: &mut [[u8; AlignedPage::SIZE]]) -> Option<&mut [Self]> {
104 // SAFETY: All bit patterns are valid
105 let (before, slice, after) = unsafe { value.align_to_mut::<Self>() };
106
107 if before.is_empty() && after.is_empty() {
108 Some(slice)
109 } else {
110 None
111 }
112 }
113
114 /// Convenient conversion from a slice of underlying representation for efficiency purposes.
115 ///
116 /// Returns `None` if not correctly aligned.
117 #[inline]
118 pub fn try_uninit_slice_mut_from_repr(
119 value: &mut [MaybeUninit<[u8; AlignedPage::SIZE]>],
120 ) -> Option<&mut [MaybeUninit<Self>]> {
121 // SAFETY: All bit patterns are valid
122 let (before, slice, after) = unsafe { value.align_to_mut::<MaybeUninit<Self>>() };
123
124 if before.is_empty() && after.is_empty() {
125 Some(slice)
126 } else {
127 None
128 }
129 }
130}
131
132/// Storage backend to be used by [`ClientDatabase`]
133///
134/// [`ClientDatabase`]: crate::ClientDatabase
135pub trait ClientDatabaseStorageBackend: fmt::Debug + Send + Sync + 'static {
136 /// Total number of pages available for reads/writes
137 fn num_pages(&self) -> u32;
138
139 // TODO: Think whether `Vec` is the right wrapper here to avoid reallocations
140 /// Reading into aligned memory.
141 ///
142 /// `length` is the number of [`AlignedPage`] units (pages) to read into (append to)
143 /// `buffer`. `offset` is in pages too.
144 fn read(
145 &self,
146 buffer: Vec<AlignedPage>,
147 length: u32,
148 offset: u32,
149 ) -> oneshot::Receiver<io::Result<Vec<AlignedPage>>>;
150
151 // TODO: Think whether `Vec` is the right wrapper here to avoid reallocations
152 /// Writing from aligned memory.
153 ///
154 /// `offset` is in [`AlignedPage`] units (pages). After successful writing returns allocated
155 /// pages back to the caller.
156 fn write(
157 &self,
158 buffer: Vec<AlignedPage>,
159 offset: u32,
160 ) -> oneshot::Receiver<io::Result<Vec<AlignedPage>>>;
161}