Skip to content

Commit

Permalink
Merge branch 'quartiq-feature/remove-all-items'
Browse files Browse the repository at this point in the history
  • Loading branch information
diondokter committed Jul 17, 2024
2 parents 1b083d1 + 75c1a1e commit e1fb263
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 7 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## Unreleased

- Added `space_left` function for queue
- Added a new `map::remove_all_items()` API to remove all stored items in flash.

# 2.0.2 07-05-24

Expand Down Expand Up @@ -127,4 +128,4 @@

## 0.1.0 - 12-01-23

- Initial release
- Initial release
111 changes: 105 additions & 6 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,21 +566,51 @@ pub async fn remove_item<K: Key, S: MultiwriteNorFlash>(
flash_range.clone(),
cache,
data_buffer,
search_key.clone()
Some(search_key.clone())
)
.await,
repair = try_repair::<K, _>(flash, flash_range.clone(), cache, data_buffer).await?
)
}

/// Fully remove all stored items. Additional calls to fetch with any key will return None until
/// new items are stored again.
///
/// <div class="warning">
/// This might be really slow!
/// </div>
///
/// <div class="warning">
///
/// *You are required to, on a given flash range, use the same [Key] type every time. You are allowed to use*
/// *multiple [Value] types. See the module-level docs for more information about this.*
///
/// </div>
pub async fn remove_all_items<K: Key, S: MultiwriteNorFlash>(
flash: &mut S,
flash_range: Range<u32>,
cache: &mut impl KeyCacheImpl<K>,
data_buffer: &mut [u8],
) -> Result<(), Error<S::Error>> {
run_with_auto_repair!(
function =
remove_item_inner::<K, _>(flash, flash_range.clone(), cache, data_buffer, None).await,
repair = try_repair::<K, _>(flash, flash_range.clone(), cache, data_buffer).await?
)
}

async fn remove_item_inner<K: Key, S: MultiwriteNorFlash>(
flash: &mut S,
flash_range: Range<u32>,
cache: &mut impl KeyCacheImpl<K>,
data_buffer: &mut [u8],
search_key: K,
search_key: Option<K>,
) -> Result<(), Error<S::Error>> {
cache.notice_key_erased(&search_key);
if let Some(key) = &search_key {
cache.notice_key_erased(key);
} else {
cache.invalidate_cache_state();
}

// Search for the last used page. We're gonna erase from the one after this first.
// If we get an early shutoff or cancellation, this will make it so that we don't return
Expand Down Expand Up @@ -620,11 +650,15 @@ async fn remove_item_inner<K: Key, S: MultiwriteNorFlash>(
item::MaybeItem::Corrupted(_, _) => continue,
item::MaybeItem::Erased(_, _) => continue,
item::MaybeItem::Present(item) => {
let (item_key, _) = K::deserialize_from(item.data())?;

let item_match = if let Some(search_key) = &search_key {
let (item_key, _) = K::deserialize_from(item.data())?;
&item_key == search_key
} else {
false
};
// If this item has the same key as the key we're trying to erase, then erase the item.
// But keep going! We need to erase everything.
if item_key == search_key {
if search_key.is_none() || item_match {
item.header
.erase_data(flash, flash_range.clone(), cache, item_address)
.await?;
Expand Down Expand Up @@ -1357,6 +1391,71 @@ mod tests {
}
}

#[test]
async fn remove_all() {
let mut flash = mock_flash::MockFlashBase::<4, 1, 4096>::new(
mock_flash::WriteCountCheck::Twice,
None,
true,
);
let mut data_buffer = AlignedBuf([0; 128]);
const FLASH_RANGE: Range<u32> = 0x0000..0x4000;

// Add some data to flash
for value in 0..10 {
for key in 0..24 {
store_item(
&mut flash,
FLASH_RANGE,
&mut cache::NoCache::new(),
&mut data_buffer,
key as u8,
&vec![key as u8; value + 2].as_slice(),
)
.await
.unwrap();
}
}

// Sanity check that we can find all the keys we just added.
for key in 0..24 {
assert!(fetch_item::<u8, &[u8], _>(
&mut flash,
FLASH_RANGE,
&mut cache::NoCache::new(),
&mut data_buffer,
key
)
.await
.unwrap()
.is_some());
}

// Remove all the items
remove_all_items::<u8, _>(
&mut flash,
FLASH_RANGE,
&mut cache::NoCache::new(),
&mut data_buffer,
)
.await
.unwrap();

// Verify that none of the keys are present in flash.
for key in 0..24 {
assert!(fetch_item::<u8, &[u8], _>(
&mut flash,
FLASH_RANGE,
&mut cache::NoCache::new(),
&mut data_buffer,
key
)
.await
.unwrap()
.is_none());
}
}

#[test]
async fn store_too_big_item() {
let mut flash = MockFlashBig::new(mock_flash::WriteCountCheck::Twice, None, true);
Expand Down

0 comments on commit e1fb263

Please sign in to comment.