# Storage This is an abstraction for nonvolatile storage. It can be used directly in a low-level manner by reading/writing buffers of given length and offsets. But it is intended to be used with the DataRecord class, which automates low-level operations, and produces an interface to in-memory objects. Storage is broken up into blocks, and each block is tagged with information about the record stored in it and all related blocks. Concrete implementations of hardware drivers that have discrete page or block sizes should use whatever division is native to the hardware, although the abstraction doesn't explicitly enforce this. Concrete implementations of Storage that do not strictly require block division can choose a block size that makes sense for the application. Data is stored in linked lists at two levels. 1) Blocks holding records are linked together to give quick record access. 2) Blocks holding data for a given record are linked together to allow non-contiguous storage of any given record. Fragmentation will not impact performance in the abstraction, although it may in a given concrete implementation that incurs a penalty for random access versus sequential. Block 0 is reserved for the driver's use. Storage will use the first free block available for write requests. DataRecords use CBOR for serialized application data. And little-endian raw binary for the Storage-observed region of the first block of a file. Like so.... // This member data is stored in an aligned binary format as the first // bytes of any record. // All block address fields are 32-bit for class simplicity, but will be // truncated to the size appropriate for the storage driver. uint8_t _version = 0; // Serializer version for this record. uint8_t _flags = 0; // Flags to describe this record. uint8_t _record_type = 0; // What this means is mostly up to the application. uint8_t _key[9] = {0, }; // Application-provided name for this record. uint32_t _hash = 0; // Autogenerated payload hash. uint32_t _data_length = 0; // How many bytes does the record occupy? uint64_t _timestamp = 0; // Creation time of the record. uint32_t _nxt_rec_addr = 0; // Address of next record (0 if this is the last record). uint32_t _nxt_dat_addr = 0; // Address of next data block for this record (0 if this is the last). This metadata format will fit inside of 32-bytes for small devices. The size of this data is the limiting factor for minimum page size supported by the Storage abstraction. Although keys are intended to be unique, the Storage abstraction doesn't enforce this condition. ## Usage example #### Dependencies