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