solana_accounts_db/
account_info.rs1use {
6 crate::{
7 accounts_db::AccountsFileId,
8 accounts_file::ALIGN_BOUNDARY_OFFSET,
9 accounts_index::{DiskIndexValue, IndexValue, IsCached},
10 is_zero_lamport::IsZeroLamport,
11 },
12 modular_bitfield::prelude::*,
13};
14
15pub type Offset = usize;
17
18#[derive(Debug, PartialEq, Eq)]
20pub enum StorageLocation {
21 AppendVec(AccountsFileId, Offset),
22 Cached,
23}
24
25impl StorageLocation {
26 pub fn is_offset_equal(&self, other: &StorageLocation) -> bool {
27 match self {
28 StorageLocation::Cached => {
29 matches!(other, StorageLocation::Cached) }
31 StorageLocation::AppendVec(_, offset) => {
32 match other {
33 StorageLocation::Cached => {
34 false }
36 StorageLocation::AppendVec(_, other_offset) => other_offset == offset,
37 }
38 }
39 }
40 }
41 pub fn is_store_id_equal(&self, other: &StorageLocation) -> bool {
42 match self {
43 StorageLocation::Cached => {
44 matches!(other, StorageLocation::Cached) }
46 StorageLocation::AppendVec(store_id, _) => {
47 match other {
48 StorageLocation::Cached => {
49 false }
51 StorageLocation::AppendVec(other_store_id, _) => other_store_id == store_id,
52 }
53 }
54 }
55 }
56}
57
58pub type OffsetReduced = u32;
62
63const CACHED_OFFSET: OffsetReduced = (1 << (OffsetReduced::BITS - 1)) - 1;
71
72#[bitfield(bits = 32)]
73#[repr(C)]
74#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
75pub struct PackedOffsetAndFlags {
76 offset_reduced: B31,
78 is_zero_lamport: bool,
80}
81
82#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
83pub struct AccountInfo {
84 store_id: AccountsFileId,
86
87 account_offset_and_flags: PackedOffsetAndFlags,
90}
91
92impl IsZeroLamport for AccountInfo {
93 fn is_zero_lamport(&self) -> bool {
94 self.account_offset_and_flags.is_zero_lamport()
95 }
96}
97
98impl IsCached for AccountInfo {
99 fn is_cached(&self) -> bool {
100 self.account_offset_and_flags.offset_reduced() == CACHED_OFFSET
101 }
102}
103
104impl IndexValue for AccountInfo {}
105
106impl DiskIndexValue for AccountInfo {}
107
108impl IsCached for StorageLocation {
109 fn is_cached(&self) -> bool {
110 matches!(self, StorageLocation::Cached)
111 }
112}
113
114const CACHE_VIRTUAL_STORAGE_ID: AccountsFileId = AccountsFileId::MAX;
116
117impl AccountInfo {
118 pub fn new(storage_location: StorageLocation, is_zero_lamport: bool) -> Self {
119 let mut packed_offset_and_flags = PackedOffsetAndFlags::default();
120 let store_id = match storage_location {
121 StorageLocation::AppendVec(store_id, offset) => {
122 let reduced_offset = Self::get_reduced_offset(offset);
123 assert_ne!(
124 CACHED_OFFSET, reduced_offset,
125 "illegal offset for non-cached item"
126 );
127 packed_offset_and_flags.set_offset_reduced(Self::get_reduced_offset(offset));
128 assert_eq!(
129 Self::reduced_offset_to_offset(packed_offset_and_flags.offset_reduced()),
130 offset,
131 "illegal offset"
132 );
133 store_id
134 }
135 StorageLocation::Cached => {
136 packed_offset_and_flags.set_offset_reduced(CACHED_OFFSET);
137 CACHE_VIRTUAL_STORAGE_ID
138 }
139 };
140 packed_offset_and_flags.set_is_zero_lamport(is_zero_lamport);
141 Self {
142 store_id,
143 account_offset_and_flags: packed_offset_and_flags,
144 }
145 }
146
147 pub fn get_reduced_offset(offset: usize) -> OffsetReduced {
148 (offset / ALIGN_BOUNDARY_OFFSET) as OffsetReduced
149 }
150
151 pub fn store_id(&self) -> AccountsFileId {
152 assert!(!self.is_cached());
154 self.store_id
155 }
156
157 pub fn offset(&self) -> Offset {
158 Self::reduced_offset_to_offset(self.account_offset_and_flags.offset_reduced())
159 }
160
161 pub fn reduced_offset_to_offset(reduced_offset: OffsetReduced) -> Offset {
162 (reduced_offset as Offset) * ALIGN_BOUNDARY_OFFSET
163 }
164
165 pub fn storage_location(&self) -> StorageLocation {
166 if self.is_cached() {
167 StorageLocation::Cached
168 } else {
169 StorageLocation::AppendVec(self.store_id, self.offset())
170 }
171 }
172}
173
174#[cfg(test)]
175mod test {
176 use {super::*, crate::append_vec::MAXIMUM_APPEND_VEC_FILE_SIZE};
177
178 #[test]
179 fn test_limits() {
180 for offset in [
181 (MAXIMUM_APPEND_VEC_FILE_SIZE - 2 * (ALIGN_BOUNDARY_OFFSET as u64)) as Offset,
186 0,
187 ALIGN_BOUNDARY_OFFSET,
188 4 * ALIGN_BOUNDARY_OFFSET,
189 ] {
190 let info = AccountInfo::new(StorageLocation::AppendVec(0, offset), true);
191 assert!(info.offset() == offset);
192 }
193 }
194
195 #[test]
196 #[should_panic(expected = "illegal offset")]
197 fn test_illegal_offset() {
198 let offset = (MAXIMUM_APPEND_VEC_FILE_SIZE - (ALIGN_BOUNDARY_OFFSET as u64)) as Offset;
199 AccountInfo::new(StorageLocation::AppendVec(0, offset), true);
200 }
201
202 #[test]
203 #[should_panic(expected = "illegal offset")]
204 fn test_alignment() {
205 let offset = 1; AccountInfo::new(StorageLocation::AppendVec(0, offset), true);
207 }
208}