Merge pull request #262 from ia0/v2_error

Return error instead of debug assert
This commit is contained in:
Julien Cretin
2021-01-19 10:09:35 +01:00
committed by GitHub
3 changed files with 67 additions and 54 deletions

View File

@@ -335,12 +335,12 @@ impl Format {
} }
/// Builds the storage representation of an init info. /// Builds the storage representation of an init info.
pub fn build_init(&self, init: InitInfo) -> WordSlice { pub fn build_init(&self, init: InitInfo) -> StoreResult<WordSlice> {
let mut word = ERASED_WORD; let mut word = ERASED_WORD;
INIT_CYCLE.set(&mut word, init.cycle); INIT_CYCLE.set(&mut word, init.cycle)?;
INIT_PREFIX.set(&mut word, init.prefix); INIT_PREFIX.set(&mut word, init.prefix)?;
WORD_CHECKSUM.set(&mut word, 0); WORD_CHECKSUM.set(&mut word, 0)?;
word.as_slice() Ok(word.as_slice())
} }
/// Returns the storage index of the compact info of a page. /// Returns the storage index of the compact info of a page.
@@ -368,36 +368,36 @@ impl Format {
} }
/// Builds the storage representation of a compact info. /// Builds the storage representation of a compact info.
pub fn build_compact(&self, compact: CompactInfo) -> WordSlice { pub fn build_compact(&self, compact: CompactInfo) -> StoreResult<WordSlice> {
let mut word = ERASED_WORD; let mut word = ERASED_WORD;
COMPACT_TAIL.set(&mut word, compact.tail); COMPACT_TAIL.set(&mut word, compact.tail)?;
WORD_CHECKSUM.set(&mut word, 0); WORD_CHECKSUM.set(&mut word, 0)?;
word.as_slice() Ok(word.as_slice())
} }
/// Builds the storage representation of an internal entry. /// Builds the storage representation of an internal entry.
pub fn build_internal(&self, internal: InternalEntry) -> WordSlice { pub fn build_internal(&self, internal: InternalEntry) -> StoreResult<WordSlice> {
let mut word = ERASED_WORD; let mut word = ERASED_WORD;
match internal { match internal {
InternalEntry::Erase { page } => { InternalEntry::Erase { page } => {
ID_ERASE.set(&mut word); ID_ERASE.set(&mut word)?;
ERASE_PAGE.set(&mut word, page); ERASE_PAGE.set(&mut word, page)?;
} }
InternalEntry::Clear { min_key } => { InternalEntry::Clear { min_key } => {
ID_CLEAR.set(&mut word); ID_CLEAR.set(&mut word)?;
CLEAR_MIN_KEY.set(&mut word, min_key); CLEAR_MIN_KEY.set(&mut word, min_key)?;
} }
InternalEntry::Marker { count } => { InternalEntry::Marker { count } => {
ID_MARKER.set(&mut word); ID_MARKER.set(&mut word)?;
MARKER_COUNT.set(&mut word, count); MARKER_COUNT.set(&mut word, count)?;
} }
InternalEntry::Remove { key } => { InternalEntry::Remove { key } => {
ID_REMOVE.set(&mut word); ID_REMOVE.set(&mut word)?;
REMOVE_KEY.set(&mut word, key); REMOVE_KEY.set(&mut word, key)?;
} }
} }
WORD_CHECKSUM.set(&mut word, 0); WORD_CHECKSUM.set(&mut word, 0)?;
word.as_slice() Ok(word.as_slice())
} }
/// Parses the first word of an entry from its storage representation. /// Parses the first word of an entry from its storage representation.
@@ -459,31 +459,31 @@ impl Format {
} }
/// Builds the storage representation of a user entry. /// Builds the storage representation of a user entry.
pub fn build_user(&self, key: Nat, value: &[u8]) -> Vec<u8> { pub fn build_user(&self, key: Nat, value: &[u8]) -> StoreResult<Vec<u8>> {
let length = usize_to_nat(value.len()); let length = usize_to_nat(value.len());
let word_size = self.word_size(); let word_size = self.word_size();
let footer = self.bytes_to_words(length); let footer = self.bytes_to_words(length);
let mut result = vec![0xff; ((1 + footer) * word_size) as usize]; let mut result = vec![0xff; ((1 + footer) * word_size) as usize];
result[word_size as usize..][..length as usize].copy_from_slice(value); result[word_size as usize..][..length as usize].copy_from_slice(value);
let mut word = ERASED_WORD; let mut word = ERASED_WORD;
ID_HEADER.set(&mut word); ID_HEADER.set(&mut word)?;
if footer > 0 && is_erased(&result[(footer * word_size) as usize..]) { if footer > 0 && is_erased(&result[(footer * word_size) as usize..]) {
HEADER_FLIPPED.set(&mut word); HEADER_FLIPPED.set(&mut word);
*result.last_mut().unwrap() = 0x7f; *result.last_mut().unwrap() = 0x7f;
} }
HEADER_LENGTH.set(&mut word, length); HEADER_LENGTH.set(&mut word, length)?;
HEADER_KEY.set(&mut word, key); HEADER_KEY.set(&mut word, key)?;
HEADER_CHECKSUM.set( HEADER_CHECKSUM.set(
&mut word, &mut word,
count_zeros(&result[(footer * word_size) as usize..]), count_zeros(&result[(footer * word_size) as usize..]),
); )?;
result[..word_size as usize].copy_from_slice(&word.as_slice()); result[..word_size as usize].copy_from_slice(&word.as_slice());
result Ok(result)
} }
/// Sets the padding bit in the first word of a user entry. /// Sets the padding bit in the first word of a user entry.
pub fn set_padding(&self, word: &mut Word) { pub fn set_padding(&self, word: &mut Word) -> StoreResult<()> {
ID_PADDING.set(word); ID_PADDING.set(word)
} }
/// Sets the deleted bit in the first word of a user entry. /// Sets the deleted bit in the first word of a user entry.

View File

@@ -42,15 +42,20 @@ impl Field {
/// Sets the value of a bit field. /// Sets the value of a bit field.
/// ///
/// # Preconditions /// # Errors
/// ///
/// - The value must fit in the bit field: `num_bits(value) < self.len`. /// - The value must fit in the bit field: `num_bits(value) < self.len`.
/// - The value must only change bits from 1 to 0: `self.get(*word) & value == value`. /// - The value must only change bits from 1 to 0: `self.get(*word) & value == value`.
pub fn set(&self, word: &mut Word, value: Nat) { pub fn set(&self, word: &mut Word, value: Nat) -> StoreResult<()> {
debug_assert_eq!(value & self.mask(), value); if value & self.mask() != value {
return Err(StoreError::InvalidStorage);
}
let mask = !(self.mask() << self.pos); let mask = !(self.mask() << self.pos);
word.0 &= mask | (value << self.pos); word.0 &= mask | (value << self.pos);
debug_assert_eq!(self.get(*word), value); if self.get(*word) != value {
return Err(StoreError::InvalidStorage);
}
Ok(())
} }
/// Returns a bit mask the length of the bit field. /// Returns a bit mask the length of the bit field.
@@ -82,8 +87,8 @@ impl ConstField {
} }
/// Sets the bit field to its value. /// Sets the bit field to its value.
pub fn set(&self, word: &mut Word) { pub fn set(&self, word: &mut Word) -> StoreResult<()> {
self.field.set(word, self.value); self.field.set(word, self.value)
} }
} }
@@ -135,15 +140,15 @@ impl Checksum {
/// Sets the checksum to the external increment value. /// Sets the checksum to the external increment value.
/// ///
/// # Preconditions /// # Errors
/// ///
/// - The bits of the checksum bit field should be set to one: `self.field.get(*word) == /// - The bits of the checksum bit field should be set to one: `self.field.get(*word) ==
/// self.field.mask()`. /// self.field.mask()`.
/// - The checksum value should fit in the checksum bit field: `num_bits(word.count_zeros() + /// - The checksum value should fit in the checksum bit field: `num_bits(word.count_zeros() +
/// value) < self.field.len`. /// value) < self.field.len`.
pub fn set(&self, word: &mut Word, value: Nat) { pub fn set(&self, word: &mut Word, value: Nat) -> StoreResult<()> {
debug_assert_eq!(self.field.get(*word), self.field.mask()); debug_assert_eq!(self.field.get(*word), self.field.mask());
self.field.set(word, word.0.count_zeros() + value); self.field.set(word, word.0.count_zeros() + value)
} }
} }
@@ -290,7 +295,7 @@ mod tests {
assert_eq!(field.get(Word(0x000000f8)), 0x1f); assert_eq!(field.get(Word(0x000000f8)), 0x1f);
assert_eq!(field.get(Word(0x0000ff37)), 6); assert_eq!(field.get(Word(0x0000ff37)), 6);
let mut word = Word(0xffffffff); let mut word = Word(0xffffffff);
field.set(&mut word, 3); field.set(&mut word, 3).unwrap();
assert_eq!(word, Word(0xffffff1f)); assert_eq!(word, Word(0xffffff1f));
} }
@@ -305,7 +310,7 @@ mod tests {
assert!(field.check(Word(0x00000048))); assert!(field.check(Word(0x00000048)));
assert!(field.check(Word(0x0000ff4f))); assert!(field.check(Word(0x0000ff4f)));
let mut word = Word(0xffffffff); let mut word = Word(0xffffffff);
field.set(&mut word); field.set(&mut word).unwrap();
assert_eq!(word, Word(0xffffff4f)); assert_eq!(word, Word(0xffffff4f));
} }
@@ -333,7 +338,7 @@ mod tests {
assert_eq!(field.get(Word(0x00ffff67)), Ok(4)); assert_eq!(field.get(Word(0x00ffff67)), Ok(4));
assert_eq!(field.get(Word(0x7fffff07)), Err(StoreError::InvalidStorage)); assert_eq!(field.get(Word(0x7fffff07)), Err(StoreError::InvalidStorage));
let mut word = Word(0x0fffffff); let mut word = Word(0x0fffffff);
field.set(&mut word, 4); field.set(&mut word, 4).unwrap();
assert_eq!(word, Word(0x0fffff47)); assert_eq!(word, Word(0x0fffff47));
} }

View File

@@ -300,7 +300,9 @@ impl<S: Storage> Store<S> {
self.reserve(self.format.transaction_capacity(updates))?; self.reserve(self.format.transaction_capacity(updates))?;
// Write the marker entry. // Write the marker entry.
let marker = self.tail()?; let marker = self.tail()?;
let entry = self.format.build_internal(InternalEntry::Marker { count }); let entry = self
.format
.build_internal(InternalEntry::Marker { count })?;
self.write_slice(marker, &entry)?; self.write_slice(marker, &entry)?;
self.init_page(marker, marker)?; self.init_page(marker, marker)?;
// Write the updates. // Write the updates.
@@ -308,7 +310,7 @@ impl<S: Storage> Store<S> {
for update in updates { for update in updates {
let length = match *update { let length = match *update {
StoreUpdate::Insert { key, ref value } => { StoreUpdate::Insert { key, ref value } => {
let entry = self.format.build_user(usize_to_nat(key), value); let entry = self.format.build_user(usize_to_nat(key), value)?;
let word_size = self.format.word_size(); let word_size = self.format.word_size();
let footer = usize_to_nat(entry.len()) / word_size - 1; let footer = usize_to_nat(entry.len()) / word_size - 1;
self.write_slice(tail, &entry[..(footer * word_size) as usize])?; self.write_slice(tail, &entry[..(footer * word_size) as usize])?;
@@ -317,7 +319,7 @@ impl<S: Storage> Store<S> {
} }
StoreUpdate::Remove { key } => { StoreUpdate::Remove { key } => {
let key = usize_to_nat(key); let key = usize_to_nat(key);
let remove = self.format.build_internal(InternalEntry::Remove { key }); let remove = self.format.build_internal(InternalEntry::Remove { key })?;
self.write_slice(tail, &remove)?; self.write_slice(tail, &remove)?;
0 0
} }
@@ -337,7 +339,9 @@ impl<S: Storage> Store<S> {
if min_key > self.format.max_key() { if min_key > self.format.max_key() {
return Err(StoreError::InvalidArgument); return Err(StoreError::InvalidArgument);
} }
let clear = self.format.build_internal(InternalEntry::Clear { min_key }); let clear = self
.format
.build_internal(InternalEntry::Clear { min_key })?;
// We always have one word available. We can't use `reserve` because this is internal // We always have one word available. We can't use `reserve` because this is internal
// capacity, not user capacity. // capacity, not user capacity.
while self.immediate_capacity()? < 1 { while self.immediate_capacity()? < 1 {
@@ -403,7 +407,7 @@ impl<S: Storage> Store<S> {
if key > self.format.max_key() || value_len > self.format.max_value_len() { if key > self.format.max_key() || value_len > self.format.max_value_len() {
return Err(StoreError::InvalidArgument); return Err(StoreError::InvalidArgument);
} }
let entry = self.format.build_user(key, value); let entry = self.format.build_user(key, value)?;
let entry_len = usize_to_nat(entry.len()); let entry_len = usize_to_nat(entry.len());
self.reserve(entry_len / self.format.word_size())?; self.reserve(entry_len / self.format.word_size())?;
let tail = self.tail()?; let tail = self.tail()?;
@@ -469,7 +473,7 @@ impl<S: Storage> Store<S> {
let init_info = self.format.build_init(InitInfo { let init_info = self.format.build_init(InitInfo {
cycle: 0, cycle: 0,
prefix: 0, prefix: 0,
}); })?;
self.storage_write_slice(index, &init_info) self.storage_write_slice(index, &init_info)
} }
@@ -681,7 +685,9 @@ impl<S: Storage> Store<S> {
} }
let tail = max(self.tail()?, head.next_page(&self.format)); let tail = max(self.tail()?, head.next_page(&self.format));
let index = self.format.index_compact(head.page(&self.format)); let index = self.format.index_compact(head.page(&self.format));
let compact_info = self.format.build_compact(CompactInfo { tail: tail - head }); let compact_info = self
.format
.build_compact(CompactInfo { tail: tail - head })?;
self.storage_write_slice(index, &compact_info)?; self.storage_write_slice(index, &compact_info)?;
self.compact_copy() self.compact_copy()
} }
@@ -721,7 +727,7 @@ impl<S: Storage> Store<S> {
self.init_page(tail, tail + (length - 1))?; self.init_page(tail, tail + (length - 1))?;
tail += length; tail += length;
} }
let erase = self.format.build_internal(InternalEntry::Erase { page }); let erase = self.format.build_internal(InternalEntry::Erase { page })?;
self.write_slice(tail, &erase)?; self.write_slice(tail, &erase)?;
self.init_page(tail, tail)?; self.init_page(tail, tail)?;
self.compact_erase(tail) self.compact_erase(tail)
@@ -851,7 +857,7 @@ impl<S: Storage> Store<S> {
let init_info = self.format.build_init(InitInfo { let init_info = self.format.build_init(InitInfo {
cycle: new_first.cycle(&self.format), cycle: new_first.cycle(&self.format),
prefix: new_first.word(&self.format), prefix: new_first.word(&self.format),
}); })?;
self.storage_write_slice(index, &init_info)?; self.storage_write_slice(index, &init_info)?;
Ok(()) Ok(())
} }
@@ -859,7 +865,7 @@ impl<S: Storage> Store<S> {
/// Sets the padding bit of a user header. /// Sets the padding bit of a user header.
fn set_padding(&mut self, pos: Position) -> StoreResult<()> { 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.format.set_padding(&mut word)?;
self.write_slice(pos, &word.as_slice())?; self.write_slice(pos, &word.as_slice())?;
Ok(()) Ok(())
} }
@@ -1195,10 +1201,12 @@ impl Store<BufferStorage> {
let format = Format::new(storage).unwrap(); let format = Format::new(storage).unwrap();
// Write the init info of the first page. // Write the init info of the first page.
let mut index = format.index_init(0); let mut index = format.index_init(0);
let init_info = format.build_init(InitInfo { let init_info = format
.build_init(InitInfo {
cycle: usize_to_nat(cycle), cycle: usize_to_nat(cycle),
prefix: 0, prefix: 0,
}); })
.unwrap();
storage.write_slice(index, &init_info).unwrap(); storage.write_slice(index, &init_info).unwrap();
// Pad the first word of the page. This makes the store looks used, otherwise we may confuse // Pad the first word of the page. This makes the store looks used, otherwise we may confuse
// it with a partially initialized store. // it with a partially initialized store.