diff --git a/examples/store_latency.rs b/examples/store_latency.rs index 0d84979..a9d714d 100644 --- a/examples/store_latency.rs +++ b/examples/store_latency.rs @@ -194,10 +194,10 @@ fn main() { write_matrix(matrix); // Results for nrf52840dk_opensk: - // StorageConfig { page_size: 4096, num_pages: 20 } + // StorageConfig { num_pages: 20 } // Overwrite Length Boot Compaction Insert Remove - // no 50 words 16.2 ms 143.8 ms 18.3 ms 8.4 ms - // yes 1 words 303.8 ms 97.9 ms 9.7 ms 4.7 ms + // no 50 words 18.6 ms 145.8 ms 21.0 ms 9.8 ms + // yes 1 words 335.8 ms 100.6 ms 11.7 ms 5.7 ms } fn align(x: &str, n: usize) { diff --git a/libraries/persistent_store/src/buffer.rs b/libraries/persistent_store/src/buffer.rs index 3acd39a..837ed72 100644 --- a/libraries/persistent_store/src/buffer.rs +++ b/libraries/persistent_store/src/buffer.rs @@ -18,7 +18,7 @@ //! actual flash storage. Instead it uses a buffer in memory to represent the storage state. use crate::{Storage, StorageError, StorageIndex, StorageResult}; -use alloc::borrow::Borrow; +use alloc::borrow::{Borrow, Cow}; use alloc::boxed::Box; use alloc::vec; @@ -301,8 +301,8 @@ impl Storage for BufferStorage { self.options.max_page_erases } - fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult<&[u8]> { - Ok(&self.storage[index.range(length, self)?]) + fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult> { + Ok(Cow::Borrowed(&self.storage[index.range(length, self)?])) } fn write_slice(&mut self, index: StorageIndex, value: &[u8]) -> StorageResult<()> { diff --git a/libraries/persistent_store/src/storage.rs b/libraries/persistent_store/src/storage.rs index fb5b0cb..adc3c53 100644 --- a/libraries/persistent_store/src/storage.rs +++ b/libraries/persistent_store/src/storage.rs @@ -14,6 +14,8 @@ //! Flash storage abstraction. +use alloc::borrow::Cow; + /// Represents a byte position in a storage. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct StorageIndex { @@ -60,7 +62,7 @@ pub trait Storage { /// Reads a byte slice from the storage. /// /// The `index` must designate `length` bytes in the storage. - fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult<&[u8]>; + fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult>; /// Writes a word slice to the storage. /// diff --git a/libraries/persistent_store/src/store.rs b/libraries/persistent_store/src/store.rs index 674bc06..b946878 100644 --- a/libraries/persistent_store/src/store.rs +++ b/libraries/persistent_store/src/store.rs @@ -25,6 +25,7 @@ use crate::{usize_to_nat, Nat, Storage, StorageError, StorageIndex}; pub use crate::{ BufferStorage, StoreDriver, StoreDriverOff, StoreDriverOn, StoreInterruption, StoreInvariant, }; +use alloc::borrow::Cow; use alloc::boxed::Box; use alloc::vec::Vec; use core::borrow::Borrow; @@ -490,7 +491,8 @@ impl Store { fn recover_initialize(&mut self) -> StoreResult<()> { let word_size = self.format.word_size(); for page in 0..self.format.num_pages() { - let (init, rest) = self.read_page(page).split_at(word_size as usize); + let content = self.read_page(page); + let (init, rest) = content.split_at(word_size as usize); if (page > 0 && !is_erased(init)) || !is_erased(rest) { return Ok(()); } @@ -890,7 +892,7 @@ impl Store { /// Sets the padding bit of a user header. fn set_padding(&mut self, pos: Position) -> StoreResult<()> { - let mut word = Word::from_slice(self.read_word(pos)); + let mut word = Word::from_slice(&self.read_word(pos)); self.format.set_padding(&mut word)?; self.write_slice(pos, &word.as_slice())?; Ok(()) @@ -898,7 +900,7 @@ impl Store { /// Sets the deleted bit of a user header. fn set_deleted(&mut self, pos: Position) -> StoreResult<()> { - let mut word = Word::from_slice(self.read_word(pos)); + let mut word = Word::from_slice(&self.read_word(pos)); self.format.set_deleted(&mut word); self.write_slice(pos, &word.as_slice())?; Ok(()) @@ -1001,13 +1003,13 @@ impl Store { 0 => None, _ => Some(self.read_word(*pos + length)), }; - if header.check(footer) { + if header.check(footer.as_deref()) { if header.key > self.format.max_key() { return Err(StoreError::InvalidStorage); } *pos += 1 + length; ParsedEntry::User(header) - } else if footer.map_or(true, |x| is_erased(x)) { + } else if footer.map_or(true, |x| is_erased(&x)) { self.parse_partial(pos) } else { *pos += 1 + length; @@ -1028,7 +1030,7 @@ impl Store { fn parse_partial(&self, pos: &mut Position) -> ParsedEntry { let mut length = None; for i in 0..self.format.max_prefix_len() { - if !is_erased(self.read_word(*pos + i)) { + if !is_erased(&self.read_word(*pos + i)) { length = Some(i); } } @@ -1045,20 +1047,20 @@ impl Store { fn parse_init(&self, page: Nat) -> StoreResult> { let index = self.format.index_init(page); let word = self.storage_read_slice(index, self.format.word_size()); - self.format.parse_init(Word::from_slice(word)) + self.format.parse_init(Word::from_slice(&word)) } /// Parses the compact info of a page. fn parse_compact(&self, page: Nat) -> StoreResult> { let index = self.format.index_compact(page); let word = self.storage_read_slice(index, self.format.word_size()); - self.format.parse_compact(Word::from_slice(word)) + self.format.parse_compact(Word::from_slice(&word)) } /// Parses a word from the virtual storage. fn parse_word(&self, pos: Position) -> StoreResult> { self.format - .parse_word(Word::from_slice(self.read_word(pos))) + .parse_word(Word::from_slice(&self.read_word(pos))) } /// Reads a slice from the virtual storage. @@ -1068,22 +1070,22 @@ impl Store { let mut result = Vec::with_capacity(length as usize); let index = pos.index(&self.format); let max_length = self.format.page_size() - usize_to_nat(index.byte); - result.extend_from_slice(self.storage_read_slice(index, min(length, max_length))); + result.extend_from_slice(&self.storage_read_slice(index, min(length, max_length))); if length > max_length { // The slice spans the next page. let index = pos.next_page(&self.format).index(&self.format); - result.extend_from_slice(self.storage_read_slice(index, length - max_length)); + result.extend_from_slice(&self.storage_read_slice(index, length - max_length)); } result } /// Reads a word from the virtual storage. - fn read_word(&self, pos: Position) -> &[u8] { + fn read_word(&self, pos: Position) -> Cow<[u8]> { self.storage_read_slice(pos.index(&self.format), self.format.word_size()) } /// Reads a physical page. - fn read_page(&self, page: Nat) -> &[u8] { + fn read_page(&self, page: Nat) -> Cow<[u8]> { let index = StorageIndex { page: page as usize, byte: 0, @@ -1092,7 +1094,7 @@ impl Store { } /// Reads a slice from the physical storage. - fn storage_read_slice(&self, index: StorageIndex, length: Nat) -> &[u8] { + fn storage_read_slice(&self, index: StorageIndex, length: Nat) -> Cow<[u8]> { // The only possible failures are if the slice spans multiple pages. self.storage.read_slice(index, length as usize).unwrap() } @@ -1142,7 +1144,7 @@ impl Store { /// Erases a page if not already erased. fn storage_erase_page(&mut self, page: Nat) -> StoreResult<()> { - if !is_erased(self.read_page(page)) { + if !is_erased(&self.read_page(page)) { self.storage.erase_page(page as usize)?; } Ok(()) diff --git a/src/env/tock/storage.rs b/src/env/tock/storage.rs index 515dab3..c2a5f03 100644 --- a/src/env/tock/storage.rs +++ b/src/env/tock/storage.rs @@ -14,6 +14,7 @@ use crate::api::upgrade_storage::helper::{find_slice, is_aligned, ModRange}; use crate::api::upgrade_storage::UpgradeStorage; +use alloc::borrow::Cow; use alloc::vec::Vec; use core::cell::Cell; use libtock_core::{callback, syscalls}; @@ -196,9 +197,9 @@ impl Storage for TockStorage { self.max_page_erases } - fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult<&[u8]> { + fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult> { let start = index.range(length, self)?.start; - find_slice(&self.storage_locations, start, length) + find_slice(&self.storage_locations, start, length).map(Cow::Borrowed) } fn write_slice(&mut self, index: StorageIndex, value: &[u8]) -> StorageResult<()> {