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