// Copyright 2020 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // This file defines classes for managing the in-flash format for KVS entires. #pragma once #include #include #include #include #include "pw_kvs/checksum.h" #include "pw_kvs/flash_memory.h" #include "pw_span/span.h" namespace pw::kvs { // EntryHeader represents a key-value entry as stored in flash. class EntryHeader { public: EntryHeader() = default; // Creates a new EntryHeader for a valid (non-deleted) entry. static EntryHeader Valid(uint32_t magic, ChecksumAlgorithm* algorithm, std::string_view key, span value, uint32_t key_version) { return EntryHeader(magic, algorithm, key, value, value.size(), key_version); } // Creates a new EntryHeader for a tombstone entry, which marks a deleted key. static EntryHeader Tombstone(uint32_t magic, ChecksumAlgorithm* algorithm, std::string_view key, uint32_t key_version) { return EntryHeader( magic, algorithm, key, {}, kDeletedValueLength, key_version); } Status VerifyChecksum(ChecksumAlgorithm* algorithm, std::string_view key, span value) const; Status VerifyChecksumInFlash(FlashPartition* partition, FlashPartition::Address header_address, ChecksumAlgorithm* algorithm) const; // Calculates the total size of the entry: header, key, and value. static constexpr size_t size(std::string_view key, span value) { return sizeof(EntryHeader) + key.size() + value.size(); } size_t size() const { return sizeof(EntryHeader) + key_length() + value_length(); } uint32_t magic() const { return magic_; } uint32_t checksum() const { return checksum_; } bool deleted() const { return (key_value_length_ >> kValueLengthShift) == kDeletedValueLength; } size_t key_length() const { return key_value_length_ & kKeyLengthMask; } void set_key_length(uint32_t key_length) { key_value_length_ = key_length | (~kKeyLengthMask & key_value_length_); } size_t value_length() const { return deleted() ? 0u : (key_value_length_ >> kValueLengthShift); } void set_value_length(uint32_t value_length) { key_value_length_ = (value_length << kValueLengthShift) | (kKeyLengthMask & key_value_length_); } uint32_t key_version() const { return key_version_; } private: static constexpr uint32_t kNoChecksum = 0; static constexpr uint32_t kKeyLengthMask = 0b111111; static constexpr uint32_t kValueLengthShift = 8; static constexpr uint32_t kDeletedValueLength = 0xFFFFFF; EntryHeader(uint32_t magic, ChecksumAlgorithm* algorithm, std::string_view key, span value, uint32_t value_length_field, uint32_t key_version); static constexpr size_t checked_data_offset() { return offsetof(EntryHeader, key_value_length_); } span checksum_bytes() const { return as_bytes(span(&checksum_, 1)); } void CalculateChecksum(ChecksumAlgorithm* algorithm, std::string_view key, span value) const; uint32_t magic_; uint32_t checksum_; // 6 bits, 0: 5 - key - maximum 64 characters // 2 bits, 6: 7 - reserved // 24 bits, 8:31 - value - maximum 16MB uint32_t key_value_length_; uint32_t key_version_; }; static_assert(sizeof(EntryHeader) == 16, "EntryHeader should have no padding"); } // namespace pw::kvs