1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 #include <span> 18 19 #include "pw_kvs/checksum.h" 20 21 namespace pw { 22 namespace kvs { 23 24 struct EntryFormat; 25 26 namespace internal { 27 28 // Disk format of the header used for each key-value entry. 29 struct EntryHeader { 30 // For KVS magic value always use a random 32 bit integer rather than a 31 // human readable 4 bytes. See pw_kvs/format.h::EntryFormat for more 32 // information. 33 uint32_t magic; 34 35 // The checksum of the entire entry, including the header, key, value, and 36 // zero-value padding bytes. The checksum is calculated as if the checksum 37 // field value was zero. 38 uint32_t checksum; 39 40 // Stores the alignment in 16-byte units, starting from 16. To calculate the 41 // number of bytes, add one to this number and multiply by 16. 42 uint8_t alignment_units; 43 44 // The length of the key in bytes. The key is not null terminated. 45 // 6 bits, 0:5 - key length - maximum 64 characters 46 // 2 bits, 6:7 - reserved 47 uint8_t key_length_bytes; 48 49 // Byte length of the value; maximum of 65534. The max uint16_t value (65535 50 // or 0xFFFF) is reserved to indicate this is a tombstone (deleted) entry. 51 uint16_t value_size_bytes; 52 53 // The transaction ID for this key. Monotonically increasing. 54 uint32_t transaction_id; 55 }; 56 57 static_assert(sizeof(EntryHeader) == 16, "EntryHeader must not have padding"); 58 59 // This class wraps EntryFormat instances to support having multiple 60 // simultaneously supported formats. 61 class EntryFormats { 62 public: EntryFormats(std::span<const EntryFormat> formats)63 explicit constexpr EntryFormats(std::span<const EntryFormat> formats) 64 : formats_(formats) {} 65 EntryFormats(const EntryFormat & format)66 explicit constexpr EntryFormats(const EntryFormat& format) 67 : formats_(&format, 1) {} 68 primary()69 const EntryFormat& primary() const { return formats_.front(); } 70 KnownMagic(uint32_t magic)71 bool KnownMagic(uint32_t magic) const { return Find(magic) != nullptr; } 72 73 const EntryFormat* Find(uint32_t magic) const; 74 75 private: 76 const std::span<const EntryFormat> formats_; 77 }; 78 79 } // namespace internal 80 81 // The EntryFormat defines properties of KVS entries that use a particular magic 82 // number. 83 struct EntryFormat { 84 // Magic is a unique constant identifier for entries. 85 // 86 // Upon reading from an address in flash, the magic number facilitiates 87 // quickly differentiating between: 88 // 89 // - Reading erased data - typically 0xFF - from flash. 90 // - Reading corrupted data 91 // - Reading a valid entry 92 // 93 // When selecting a magic for your particular KVS, pick a random 32 bit 94 // integer rather than a human readable 4 bytes. This decreases the 95 // probability of a collision with a real string when scanning in the case of 96 // corruption. To generate such a number: 97 /* 98 $ python3 -c 'import random; print(hex(random.randint(0,2**32)))' 99 0xaf741757 100 */ 101 uint32_t magic; 102 103 // The checksum algorithm is used to calculate checksums for KVS entries. If 104 // it is null, no checksum is used. 105 ChecksumAlgorithm* checksum; 106 }; 107 108 } // namespace kvs 109 } // namespace pw 110