# Context
For embedded devices, it might be desirable to persist sensor reads or other data across power cycles. The typical approach to doing this is to not store any data locally at all, instead using wireless or other networking technologies to offload persistence of data to external systems. However, this has many constraints. The embedded device must have networking or other communication capabilities. This has many implications for the context in which the device may be used. Networks are complicated to set up and maintain and are typically **not** static over time, increasing the complexity of the software that must run on the embedded system. Further, it requires that the entity that controls the network allows traffic between the embedded device and the target for data persistence. While this may be acceptable in many situations, it is likewise not acceptable in many more. What if the purpose of the data is meant to provide incite into the state of the device before failure to the manufacturer? What if the device is expected to move and not always be able to communicate with the network?
In short, there are many use-cases for buffering data on an embedded device. Some subset of these cases also require that the data persist between power cycles. To support that, data must be persisted to non-volatile storage.
Non-volatile storage options that are typically available to low power embedded systems include mediums such as SPI flash, eMMC modules, Micro SD cards, etc.. Most, if not all, options these days utilize flash in some capacity, which is typically rated for a certain number of read-write cycles before wearing out and being unable to be used further. Many newer flash mediums support a technique called "wear leveling" which is embedded into the controller firmware of the flash device and spreads write operations out across the blocks flash memory so as to maximize the longevity of the device as a whole. However, not all options support wear leveling. SPI Flash and cheaper Micro SD cards, for example, typically do not. This pushes the concern of maximizing flash lifespan to the programmer.
There are two main issues to be concerned about when attempting to maximize flash longevity: write aligned to *page* size (note: **not** block size), and minimize write-amplification as much as possible, particularly to the same addresses/offsets on the flash storage.
# Design
To support this I propose a new data-structure heavily based on simple [[Ring Buffer]]s with the following properties:
1. All records within the buffer are page aligned
2. The buffer must have an even number of records contained
3. Header is page-sized, contains only information that is static/exists for the lifetime of the buffer
4. A sequence number appended to the *tail* of each record
- This still contributes to the total size, so as to keep records *page* aligned
The first requirement should be self-explanatory. If records are page aligned, each update of that record's slot will only take one clear-write cycle from the underlying flash cells.
> [!note]
> Page size is the unit of deletion for a storage medium. Block size is the unit of reading and is typically the standard unit of writing on [[Linux]].
The third requirement is is for the same reason. One thing to note here is the header will only be written once, when the buffer is created and initialized. It may be changed, but such changes would mean that data in the buffer is considered lost.
Typical page size is 4kB, but may be much larger; as large as 16MB has been found on some Micro SD cards.
The motivation behind numbers 2 and 4 will be covered in the next section.
## Algorithm