Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/store_latency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions libraries/persistent_store/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<Cow<[u8]>> {
Ok(Cow::Borrowed(&self.storage[index.range(length, self)?]))
}

fn write_slice(&mut self, index: StorageIndex, value: &[u8]) -> StorageResult<()> {
Expand Down
7 changes: 6 additions & 1 deletion libraries/persistent_store/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -60,7 +62,10 @@ 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]>;
///
/// Note that we use `Cow` just because it derefs to `[u8]`. We don't really need the fact that
/// one can convert it to a `Vec`. In particular we don't do it in the store implementation.
fn read_slice(&self, index: StorageIndex, length: usize) -> StorageResult<Cow<[u8]>>;

/// Writes a word slice to the storage.
///
Expand Down
32 changes: 17 additions & 15 deletions libraries/persistent_store/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -490,7 +491,8 @@ impl<S: Storage> Store<S> {
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(());
}
Expand Down Expand Up @@ -890,15 +892,15 @@ impl<S: Storage> Store<S> {

/// 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(())
}

/// 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(())
Expand Down Expand Up @@ -1001,13 +1003,13 @@ impl<S: Storage> Store<S> {
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;
Expand All @@ -1028,7 +1030,7 @@ impl<S: Storage> Store<S> {
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);
}
}
Expand All @@ -1045,20 +1047,20 @@ impl<S: Storage> Store<S> {
fn parse_init(&self, page: Nat) -> StoreResult<WordState<InitInfo>> {
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<WordState<CompactInfo>> {
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<WordState<ParsedWord>> {
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.
Expand All @@ -1068,22 +1070,22 @@ impl<S: Storage> Store<S> {
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,
Expand All @@ -1092,7 +1094,7 @@ impl<S: Storage> Store<S> {
}

/// 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()
}
Expand Down Expand Up @@ -1142,7 +1144,7 @@ impl<S: Storage> Store<S> {

/// 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(())
Expand Down
5 changes: 3 additions & 2 deletions src/env/tock/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<Cow<[u8]>> {
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<()> {
Expand Down