C/C++ API Reference
Loading...
Searching...
No Matches
key_value_store.h
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 <array>
17#include <cstddef>
18#include <cstdint>
19#include <string_view>
20#include <type_traits>
21
22#include "pw_containers/vector.h"
23#include "pw_kvs/checksum.h"
24#include "pw_kvs/flash_memory.h"
25#include "pw_kvs/format.h"
26#include "pw_kvs/internal/entry.h"
27#include "pw_kvs/internal/entry_cache.h"
28#include "pw_kvs/internal/key_descriptor.h"
29#include "pw_kvs/internal/sectors.h"
30#include "pw_kvs/internal/span_traits.h"
31#include "pw_span/span.h"
32#include "pw_status/status.h"
33#include "pw_status/status_with_size.h"
34
35namespace pw {
36
38
40namespace kvs {
41
42enum class GargbageCollectOnWrite {
43 // Disable all automatic garbage collection on write.
44 kDisabled,
45
46 // Allow up to a single sector, if needed, to be garbage collected on write.
47 kOneSector,
48
49 // Allow as many sectors as needed be garbage collected on write.
50 kAsManySectorsNeeded,
51};
52
53enum class ErrorRecovery {
54 // Immediately do full recovery of any errors that are detected.
55 kImmediate,
56
57 // Recover from errors, but delay time consuming recovery steps until later
58 // as part of other time consuming operations. Such as waiting to garbage
59 // collect sectors with corrupt entries until the next garbage collection.
60 kLazy,
61
62 // Only recover from errors when manually triggered as part of maintenance
63 // operations. This is not recommended for normal use, only for test or
64 // read-only use.
65 kManual,
66};
67
68struct Options {
69 // Perform garbage collection if necessary when writing. If not kDisabled,
70 // garbage collection is attempted if space for an entry cannot be found. This
71 // is a relatively lengthy operation. If kDisabled, Put calls that would
72 // require garbage collection fail with RESOURCE_EXHAUSTED.
73 GargbageCollectOnWrite gc_on_write =
74 GargbageCollectOnWrite::kAsManySectorsNeeded;
75
76 // When the KVS handles errors that are discovered, such as corrupt entries,
77 // not enough redundant copys of an entry, etc.
78 ErrorRecovery recovery = ErrorRecovery::kLazy;
79
80 // Verify an entry's checksum after reading it from flash.
81 bool verify_on_read = true;
82
83 // Verify an in-flash entry's checksum after writing it.
84 bool verify_on_write = true;
85};
86
112 public:
128
129 bool initialized() const {
130 return initialized_ == InitializationState::kReady;
131 }
132
165 StatusWithSize Get(std::string_view key,
166 span<std::byte> value,
167 size_t offset_bytes = 0) const;
168
175 template <typename Pointer,
176 typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
177 Status Get(const std::string_view& key, const Pointer& pointer) const {
178 using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
179 CheckThatObjectCanBePutOrGet<T>();
180 return FixedSizeGet(key, pointer, sizeof(T));
181 }
182
213 template <typename T,
214 typename std::enable_if_t<ConvertsToSpan<T>::value>* = nullptr>
215 Status Put(const std::string_view& key, const T& value) {
216 return PutBytes(key, as_bytes(internal::make_span(value)));
217 }
218
219 template <typename T,
220 typename std::enable_if_t<!ConvertsToSpan<T>::value>* = nullptr>
221 Status Put(const std::string_view& key, const T& value) {
222 CheckThatObjectCanBePutOrGet<T>();
223 return PutBytes(key, as_bytes(span<const T>(&value, 1)));
224 }
225
249 Status Delete(std::string_view key);
250
271 StatusWithSize ValueSize(std::string_view key) const;
272
282 return FullMaintenanceHelper(MaintenanceType::kHeavy);
283 }
284
293 return FullMaintenanceHelper(MaintenanceType::kRegular);
294 }
295
301
302 void LogDebugInfo() const;
303
304 // Classes and functions to support STL-style iteration.
305 class iterator;
306
308 class Item {
309 public:
311 const char* key() const { return key_buffer_.data(); }
312
316 size_t offset_bytes = 0) const {
317 return kvs_.Get(key(), *iterator_, value_buffer, offset_bytes);
318 }
319
320 template <typename Pointer,
321 typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
322 Status Get(const Pointer& pointer) const {
323 using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
324 CheckThatObjectCanBePutOrGet<T>();
325 return kvs_.FixedSizeGet(key(), *iterator_, pointer, sizeof(T));
326 }
327
328 // Reads the size of the value referred to by this iterator. Equivalent to
329 // KeyValueStore::ValueSize.
330 StatusWithSize ValueSize() const { return kvs_.ValueSize(*iterator_); }
331
332 private:
333 friend class iterator;
334
335 constexpr Item(const KeyValueStore& kvs,
336 const internal::EntryCache::const_iterator& item_iterator)
337 : kvs_(kvs), iterator_(item_iterator), key_buffer_{} {}
338
339 void ReadKey();
340
341 const KeyValueStore& kvs_;
342 internal::EntryCache::const_iterator iterator_;
343
344 // Buffer large enough for a null-terminated version of any valid key.
345 std::array<char, internal::Entry::kMaxKeyLength + 1> key_buffer_;
346 };
347
349 class iterator {
350 public:
353
356 const iterator original(item_.kvs_, item_.iterator_);
357 operator++();
358 return original;
359 }
360
362 const Item& operator*() {
363 item_.ReadKey();
364 return item_;
365 }
366
368 const Item* operator->() { return &operator*(); }
369
371 constexpr bool operator==(const iterator& rhs) const {
372 return item_.iterator_ == rhs.item_.iterator_;
373 }
374
376 constexpr bool operator!=(const iterator& rhs) const {
377 return item_.iterator_ != rhs.item_.iterator_;
378 }
379
380 private:
381 friend class KeyValueStore;
382
383 constexpr iterator(
384 const KeyValueStore& kvs,
385 const internal::EntryCache::const_iterator& item_iterator)
386 : item_(kvs, item_iterator) {}
387
388 Item item_;
389 };
390
391 using const_iterator = iterator; // Standard alias for iterable types.
392
396 iterator end() const { return iterator(*this, entry_cache_.end()); }
397
399 size_t size() const { return entry_cache_.present_entries(); }
400
404 return entry_cache_.total_entries();
405 }
406
408 size_t max_size() const { return entry_cache_.max_entries(); }
409
411 size_t empty() const { return size() == 0u; }
412
416 uint32_t transaction_count() const { return last_transaction_id_; }
417
438 };
439
443
446 size_t redundancy() const { return entry_cache_.redundancy(); }
447
449 bool error_detected() const { return error_detected_; }
450
453 return max_key_value_size_bytes(partition_.sector_size_bytes());
454 }
455
458 static constexpr size_t max_key_value_size_bytes(
459 size_t partition_sector_size_bytes) {
460 return partition_sector_size_bytes - Entry::entry_overhead();
461 }
462
466
467 protected:
468 using Address = FlashPartition::Address;
469 using Entry = internal::Entry;
470 using KeyDescriptor = internal::KeyDescriptor;
471 using SectorDescriptor = internal::SectorDescriptor;
472
473 // In the future, will be able to provide additional EntryFormats for
474 // backwards compatibility.
475 KeyValueStore(FlashPartition* partition,
477 const Options& options,
478 size_t redundancy,
479 Vector<SectorDescriptor>& sector_descriptor_list,
480 const SectorDescriptor** temp_sectors_to_skip,
481 Vector<KeyDescriptor>& key_descriptor_list,
482 Address* addresses);
483
484 private:
485 using EntryMetadata = internal::EntryMetadata;
486 using EntryState = internal::EntryState;
487
488 template <typename T>
489 static constexpr void CheckThatObjectCanBePutOrGet() {
490 static_assert(
491 std::is_trivially_copyable<T>::value && !std::is_pointer<T>::value,
492 "Only trivially copyable, non-pointer objects may be Put and Get by "
493 "value. Any value may be stored by converting it to a byte span "
494 "with as_bytes(span(&value, 1)) or "
495 "as_writable_bytes(span(&value, 1)).");
496 }
497
498 Status InitializeMetadata();
499 Status LoadEntry(Address entry_address, Address* next_entry_address);
500 Status ScanForEntry(const SectorDescriptor& sector,
501 Address start_address,
502 Address* next_entry_address);
503
504 // Remove deleted keys from the entry cache, including freeing sector bytes
505 // used by those keys. This must only be done directly after a full garbage
506 // collection, otherwise the current deleted entry could be garbage
507 // collected before the older stale entry producing a window for an
508 // invalid/corrupted KVS state if there was a power-fault, crash or other
509 // interruption.
510 Status RemoveDeletedKeyEntries();
511
512 Status PutBytes(std::string_view key, span<const std::byte> value);
513
514 StatusWithSize ValueSize(const EntryMetadata& metadata) const;
515
516 Status ReadEntry(const EntryMetadata& metadata, Entry& entry) const;
517
518 // Finds the metadata for an entry matching a particular key. Searches for a
519 // KeyDescriptor that matches this key and sets *metadata_out to point to it
520 // if one is found.
521 //
522 // OK: there is a matching descriptor and *metadata is set
523 // NOT_FOUND: there is no descriptor that matches this key, but this key
524 // has a unique hash (and could potentially be added to the
525 // KVS)
526 // ALREADY_EXISTS: there is no descriptor that matches this key, but the
527 // key's hash collides with the hash for an existing
528 // descriptor
529 //
530 Status FindEntry(std::string_view key, EntryMetadata* metadata_out) const;
531
532 // Searches for a KeyDescriptor that matches this key and sets *metadata_out
533 // to point to it if one is found.
534 //
535 // OK: there is a matching descriptor and *metadata_out is set
536 // NOT_FOUND: there is no descriptor that matches this key
537 //
538 Status FindExisting(std::string_view key, EntryMetadata* metadata_out) const;
539
540 StatusWithSize Get(std::string_view key,
541 const EntryMetadata& metadata,
542 span<std::byte> value_buffer,
543 size_t offset_bytes) const;
544
545 Status FixedSizeGet(std::string_view key,
546 void* value,
547 size_t size_bytes) const;
548
549 Status FixedSizeGet(std::string_view key,
550 const EntryMetadata& metadata,
551 void* value,
552 size_t size_bytes) const;
553
554 Status CheckWriteOperation(std::string_view key) const;
555 Status CheckReadOperation(std::string_view key) const;
556
557 Status WriteEntryForExistingKey(EntryMetadata& metadata,
558 EntryState new_state,
559 std::string_view key,
561
562 Status WriteEntryForNewKey(std::string_view key, span<const std::byte> value);
563
564 Status WriteEntry(std::string_view key,
566 EntryState new_state,
567 EntryMetadata* prior_metadata = nullptr,
568 const internal::Entry* prior_entry = nullptr);
569
570 EntryMetadata CreateOrUpdateKeyDescriptor(const Entry& new_entry,
571 std::string_view key,
572 EntryMetadata* prior_metadata,
573 size_t prior_size);
574
575 EntryMetadata UpdateKeyDescriptor(const Entry& entry,
576 Address new_address,
577 EntryMetadata* prior_metadata,
578 size_t prior_size);
579
580 Status GetAddressesForWrite(Address* write_addresses, size_t write_size);
581
582 Status GetSectorForWrite(SectorDescriptor** sector,
583 size_t entry_size,
584 span<const Address> reserved_addresses);
585
586 Status MarkSectorCorruptIfNotOk(Status status, SectorDescriptor* sector);
587
588 Status AppendEntry(const Entry& entry,
589 std::string_view key,
591
592 StatusWithSize CopyEntryToSector(Entry& entry,
593 SectorDescriptor* new_sector,
594 Address new_address);
595
596 Status RelocateEntry(const EntryMetadata& metadata,
597 KeyValueStore::Address& address,
598 span<const Address> reserved_addresses);
599
600 // Perform all maintenance possible, including all neeeded repairing of
601 // corruption and garbage collection of reclaimable space in the KVS. When
602 // configured for manual recovery, this is the only way KVS repair is
603 // triggered.
604 //
605 // - Regular will not garbage collect sectors with valid data unless the KVS
606 // is mostly full.
607 // - Heavy will garbage collect all reclaimable space regardless of valid data
608 // in the sector.
609 enum class MaintenanceType {
610 kRegular,
611 kHeavy,
612 };
613 Status FullMaintenanceHelper(MaintenanceType maintenance_type);
614
615 // Find and garbage collect a singe sector that does not include a reserved
616 // address.
617 Status GarbageCollect(span<const Address> reserved_addresses);
618
619 Status RelocateKeyAddressesInSector(SectorDescriptor& sector_to_gc,
620 const EntryMetadata& metadata,
621 span<const Address> reserved_addresses);
622
623 Status GarbageCollectSector(SectorDescriptor& sector_to_gc,
624 span<const Address> reserved_addresses);
625
626 // Ensure that all entries are on the primary (first) format. Entries that are
627 // not on the primary format are rewritten.
628 //
629 // Return: status + number of entries updated.
630 StatusWithSize UpdateEntriesToPrimaryFormat();
631
632 Status AddRedundantEntries(EntryMetadata& metadata);
633
634 Status RepairCorruptSectors();
635
636 Status EnsureFreeSectorExists();
637
638 Status EnsureEntryRedundancy();
639
640 Status FixErrors();
641
642 Status Repair();
643
644 internal::Entry CreateEntry(Address address,
645 std::string_view key,
647 EntryState state);
648
649 void LogSectors() const;
650 void LogKeyDescriptor() const;
651
652 FlashPartition& partition_;
653 const internal::EntryFormats formats_;
654
655 // List of sectors used by this KVS.
656 internal::Sectors sectors_;
657
658 // Unordered list of KeyDescriptors. Finding a key requires scanning and
659 // verifying a match by reading the actual entry.
660 internal::EntryCache entry_cache_;
661
662 Options options_;
663
664 // Threshold value for when to garbage collect all stale data. Above the
665 // threshold, GC all reclaimable bytes regardless of if valid data is in
666 // sector. Below the threshold, only GC sectors with reclaimable bytes and no
667 // valid bytes. The threshold is based on the portion of KVS capacity used by
668 // valid bytes.
669 static constexpr size_t kGcUsageThresholdPercentage = 70;
670
671 enum class InitializationState {
672 // KVS Init() has not been called and KVS is not usable.
673 kNotInitialized,
674
675 // KVS Init() run but not all the needed invariants are met for an operating
676 // KVS. KVS is not writable, but read operaions are possible.
677 kNeedsMaintenance,
678
679 // KVS is fully ready for use.
680 kReady,
681 };
682 InitializationState initialized_;
683
684 // error_detected_ needs to be set from const KVS methods (such as Get), so
685 // make it mutable.
686 mutable bool error_detected_;
687
688 struct InternalStats {
689 size_t sector_erase_count;
690 size_t corrupt_sectors_recovered;
691 size_t missing_redundant_entries_recovered;
692 };
693 InternalStats internal_stats_;
694
695 uint32_t last_transaction_id_;
696};
697
698template <size_t kMaxEntries,
699 size_t kMaxUsableSectors,
700 size_t kRedundancy = 1,
701 size_t kEntryFormats = 1>
703 public:
704 // Constructs a KeyValueStore on the partition, with support for one
705 // EntryFormat (kEntryFormats must be 1).
706 KeyValueStoreBuffer(FlashPartition* partition,
707 const EntryFormat& format,
708 const Options& options = {})
710 partition,
712 reinterpret_cast<const EntryFormat (&)[1]>(format)),
713 options) {
714 static_assert(kEntryFormats == 1,
715 "kEntryFormats EntryFormats must be specified");
716 }
717
718 // Constructs a KeyValueStore on the partition. Supports multiple entry
719 // formats. The first EntryFormat is used for new entries.
720 KeyValueStoreBuffer(FlashPartition* partition,
722 const Options& options = {})
723 : KeyValueStore(partition,
724 formats_,
725 options,
726 kRedundancy,
727 sectors_,
728 temp_sectors_to_skip_,
729 key_descriptors_,
730 addresses_),
731 sectors_(),
732 key_descriptors_(),
733 formats_() {
734 std::copy(formats.begin(), formats.end(), formats_.begin());
735 }
736
737 private:
738 static_assert(kMaxEntries > 0u);
739 static_assert(kMaxUsableSectors > 0u);
740 static_assert(kRedundancy > 0u);
741 static_assert(kEntryFormats > 0u);
742
744
745 // Allocate space for an list of SectorDescriptors to avoid while searching
746 // for space to write entries. This is used to avoid changing sectors that are
747 // reserved for a new entry or marked as having other redundant copies of an
748 // entry. Up to kRedundancy sectors are reserved for a new entry, and up to
749 // kRedundancy - 1 sectors can have redundant copies of an entry, giving a
750 // maximum of 2 * kRedundancy - 1 sectors to avoid.
751 const SectorDescriptor* temp_sectors_to_skip_[2 * kRedundancy - 1];
752
753 // KeyDescriptors for use by the KVS's EntryCache.
754 Vector<KeyDescriptor, kMaxEntries> key_descriptors_;
755
756 // An array of addresses associated with the KeyDescriptors for use with the
757 // EntryCache. To support having KeyValueStores with different redundancies,
758 // the addresses are stored in a parallel array instead of inside
759 // KeyDescriptors.
760 internal::EntryCache::AddressList<kRedundancy, kMaxEntries> addresses_;
761
762 // EntryFormats that can be read by this KeyValueStore.
763 std::array<EntryFormat, kEntryFormats> formats_;
764};
765
766} // namespace kvs
767} // namespace pw
Definition: status.h:109
Definition: status_with_size.h:51
Definition: vector.h:65
Representation of a key-value entry during iteration.
Definition: key_value_store.h:308
Supported iteration methods.
Definition: key_value_store.h:349
Definition: key_value_store.h:702
Definition: key_value_store.h:111
Definition: span_impl.h:235
iterator end() const
Definition: key_value_store.h:396
size_t max_key_value_size_bytes() const
Definition: key_value_store.h:452
StatusWithSize ValueSize(std::string_view key) const
size_t max_size() const
Definition: key_value_store.h:408
StatusWithSize Get(span< std::byte > value_buffer, size_t offset_bytes=0) const
Definition: key_value_store.h:315
uint32_t transaction_count() const
Definition: key_value_store.h:416
const Item * operator->()
Reads the entry into the Item object.
Definition: key_value_store.h:368
iterator operator++(int)
Increments to the next key-value entry in the container.
Definition: key_value_store.h:355
const char * key() const
Definition: key_value_store.h:311
size_t sector_erase_count
The total count of individual sector erases that have been performed.
Definition: key_value_store.h:432
StatusWithSize Get(std::string_view key, span< std::byte > value, size_t offset_bytes=0) const
constexpr bool operator!=(const iterator &rhs) const
Inequality comparison of two entries.
Definition: key_value_store.h:376
const Item & operator*()
Reads the entry's key from flash.
Definition: key_value_store.h:362
size_t size() const
Definition: key_value_store.h:399
size_t corrupt_sectors_recovered
The number of corrupt sectors that have been recovered.
Definition: key_value_store.h:434
size_t redundancy() const
Definition: key_value_store.h:446
size_t writable_bytes
Definition: key_value_store.h:424
Status FullMaintenance()
Definition: key_value_store.h:292
bool error_detected() const
Definition: key_value_store.h:449
size_t empty() const
Definition: key_value_store.h:411
Status Delete(std::string_view key)
Status Put(const std::string_view &key, const T &value)
Definition: key_value_store.h:215
Status HeavyMaintenance()
Definition: key_value_store.h:281
iterator begin() const
size_t reclaimable_bytes
Definition: key_value_store.h:430
constexpr bool operator==(const iterator &rhs) const
Equality comparison of two entries.
Definition: key_value_store.h:371
iterator & operator++()
Increments to the next key-value entry in the container.
size_t in_use_bytes
The number of bytes in the KVS that are already in use.
Definition: key_value_store.h:426
Status Get(const std::string_view &key, const Pointer &pointer) const
Definition: key_value_store.h:177
StorageStats GetStorageStats() const
size_t missing_redundant_entries_recovered
Definition: key_value_store.h:437
size_t total_entries_with_deleted() const
Definition: key_value_store.h:403
static constexpr size_t max_key_value_size_bytes(size_t partition_sector_size_bytes)
Definition: key_value_store.h:458
The Pigweed namespace.
Definition: alignment.h:27
Definition: key_value_store.h:421
Definition: key_value_store.h:68