Expand description
Implements a log storage abstraction for storing persistent data in flash.
Data entries can be appended to the end of a log and read back in-order. Logs may be linear (denying writes when full) or circular (overwriting the oldest entries with the newest entries when the underlying flash volume is full). The storage volumes that logs operate upon are statically allocated at compile time and cannot be dynamically created at runtime.
Entries can be identified and seeked-to with their unique Entry IDs. Entry IDs maintain the
ordering of the underlying entries, and an entry with a larger entry ID is newer and comes
after an entry with a smaller ID. IDs can also be used to determine the physical position of
entries within the log’s underlying storage volume - taking the ID modulo the size of the
underlying storage volume yields the position of the entry’s header relative to the start of
the volume. Entries should not be created manually by clients, only retrieved through the
log_start()
, log_end()
, and next_read_entry_id()
functions.
Entry IDs are not explicitly stored in the log. Instead, each page of the log contains a header containing the page’s offset relative to the start of the log (i.e. if the page size is 512 bytes, then page #0 will have an offset of 0, page #1 an offset of 512, etc.). The offsets continue to increase even after a circular log wraps around (so if 5 512-byte pages of data are written to a 4 page log, then page #0 will now have an offset of 2048). Thus, the ID of an entry can be calculated by taking the offset of the page within the log and adding the offset of the entry within the page to find the position of the entry within the log (which is the ID). Entries also have a header of their own, which contains the length of the entry.
Logs support the following basic operations: * Read: Read back previously written entries in whole. Entries are read in their entirety (no partial reads) from oldest to newest. * Seek: Seek to different entries to begin reading from a different entry (can only seek to the start of entries). * Append: Append new data entries onto the end of a log. Can fail if the new entry is too large to fit within the log. * Sync: Sync a log to flash to ensure that all changes are persistent. * Erase: Erase a log in its entirety, clearing the underlying flash volume. See the documentation for each individual function for more detail on how they operate.
Note that while logs persist across reboots, they will be erased upon flashing a new kernel.
§Usage
storage_volume!(VOLUME, 2);
static mut PAGEBUFFER: sam4l::flashcalw::Sam4lPage = sam4l::flashcalw::Sam4lPage::new();
let log = static_init!(
capsules::log::Log,
capsules::log::Log::new(
&VOLUME,
&mut sam4l::flashcalw::FLASH_CONTROLLER,
&mut PAGEBUFFER,
true
)
);
log.register();
kernel::hil::flash::HasClient::set_client(&sam4l::flashcalw::FLASH_CONTROLLER, log);
log.set_read_client(log_storage_read_client);
log.set_append_client(log_storage_append_client);
Structs§
Constants§
- Maximum entry header size.
- Maximum page header size.