pw_kvs: Transaction count; Reset function
- Expose the transaction count, which may be useful for metrics.
- Create Reset function that resets all state that must be initialized.
- Call Reset in the constructor and at the start of Init.
Change-Id: I22ef4b949ff5b60bfc0ebc311fd0a3ccffc7b456
diff --git a/pw_kvs/key_value_store.cc b/pw_kvs/key_value_store.cc
index 4268ede..ca49b5c 100644
--- a/pw_kvs/key_value_store.cc
+++ b/pw_kvs/key_value_store.cc
@@ -44,11 +44,15 @@
const Options& options)
: partition_(*partition),
entry_header_format_(format),
- options_(options),
key_descriptors_(key_descriptor_list),
- sectors_(sector_descriptor_list) {}
+ sectors_(sector_descriptor_list),
+ options_(options) {
+ Reset();
+}
Status KeyValueStore::Init() {
+ Reset();
+
INF("Initializing key value store");
if (partition_.sector_count() > sectors_.max_size()) {
ERR("KVS init failed: kMaxUsableSectors (=%zu) must be at least as "
@@ -58,10 +62,6 @@
return Status::FAILED_PRECONDITION;
}
- // Reset descriptor lists. Key descriptors will be filled later.
- sectors_.resize(partition_.sector_count());
- key_descriptors_.clear();
-
const size_t sector_size_bytes = partition_.sector_size_bytes();
if (working_buffer_.size() < sector_size_bytes) {
@@ -75,10 +75,12 @@
DBG("First pass: Read all entries from all sectors");
Address sector_address = 0;
+ sectors_.assign(partition_.sector_count(),
+ SectorDescriptor(sector_size_bytes));
+
for (SectorDescriptor& sector : sectors_) {
// Reset the sector's valid and writable byte counts. These will be updated
// after reading each entry.
- sector.Reset(sector_size_bytes);
Address entry_address = sector_address;
for (int num_entries_in_sector = 0; true; num_entries_in_sector++) {
@@ -129,7 +131,6 @@
DBG("Second pass: Count valid bytes in each sector");
const KeyDescriptor* newest_key = nullptr;
- last_transaction_id_ = 0;
// For every valid key, increment the valid bytes for that sector.
for (KeyDescriptor& key_descriptor : key_descriptors_) {
@@ -379,7 +380,7 @@
if (InvalidKey(key)) {
return Status::INVALID_ARGUMENT;
}
- if (!initialized_) {
+ if (!initialized()) {
return Status::FAILED_PRECONDITION;
}
return Status::OK;
@@ -526,8 +527,7 @@
as_bytes(value),
key_descriptor.state()));
- // Do the valid bytes accounting for the sector the entry was relocated out
- // of.
+ // Do the valid bytes accounting for the sector the entry was relocated from.
old_sector->RemoveValidBytes(entry.size());
return Status::OK;
@@ -736,7 +736,7 @@
std::string_view key,
span<const byte> value,
KeyDescriptor::State state) {
- const uint32_t transaction_id = ++last_transaction_id_;
+ last_transaction_id_ += 1;
if (state == KeyDescriptor::kDeleted) {
return Entry::Tombstone(partition_,
@@ -745,7 +745,7 @@
entry_header_format_.checksum,
key,
partition_.alignment_bytes(),
- transaction_id);
+ last_transaction_id_);
}
return Entry::Valid(partition_,
address,
@@ -754,7 +754,14 @@
key,
value,
partition_.alignment_bytes(),
- transaction_id);
+ last_transaction_id_);
+}
+
+void KeyValueStore::Reset() {
+ initialized_ = false;
+ key_descriptors_.clear();
+ last_new_sector_ = nullptr;
+ last_transaction_id_ = 0;
}
void KeyValueStore::LogDebugInfo() {
diff --git a/pw_kvs/public/pw_kvs/internal/sector_descriptor.h b/pw_kvs/public/pw_kvs/internal/sector_descriptor.h
index 79b79b5..340ede3 100644
--- a/pw_kvs/public/pw_kvs/internal/sector_descriptor.h
+++ b/pw_kvs/public/pw_kvs/internal/sector_descriptor.h
@@ -21,11 +21,11 @@
// Tracks the available and used space in each sector used by the KVS.
class SectorDescriptor {
public:
- // Resets the sector by marking all bytes as writable with zero valid bytes.
- void Reset(uint16_t sector_size_bytes) {
- tail_free_bytes_ = sector_size_bytes;
- valid_bytes_ = 0;
- }
+ explicit constexpr SectorDescriptor(uint16_t sector_size_bytes)
+ : tail_free_bytes_(sector_size_bytes), valid_bytes_(0) {}
+
+ SectorDescriptor(const SectorDescriptor&) = default;
+ SectorDescriptor& operator=(const SectorDescriptor&) = default;
// The number of bytes available to be written in this sector.
size_t writable_bytes() const { return tail_free_bytes_; }
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index d6a6768..c8c8c2e 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -227,6 +227,11 @@
size_t empty() const { return size() == 0u; }
+ // Returns the number of transactions that have occurred since the KVS was
+ // first used. This value is retained across initializations, but is reset if
+ // the underlying flash is erased.
+ uint32_t transaction_count() const { return last_transaction_id_; }
+
protected:
using Address = FlashPartition::Address;
using KeyDescriptor = internal::KeyDescriptor;
@@ -334,16 +339,13 @@
span<const std::byte> value,
KeyDescriptor::State state);
+ void Reset();
+
void LogSectors() const;
void LogKeyDescriptor() const;
FlashPartition& partition_;
- EntryHeaderFormat entry_header_format_;
- Options options_;
-
- // TODO: To allow setting kMaxEntries and kMaxUsableSectors, these vectors
- // should instead be Vector<KeyDescriptor>& and Vector<SectorDescriptor>& that
- // refer to vectors in a templated derived class.
+ const EntryHeaderFormat entry_header_format_;
// Unordered list of KeyDescriptors. Finding a key requires scanning and
// verifying a match by reading the actual entry.
@@ -352,6 +354,10 @@
// List of sectors used by this KVS.
Vector<SectorDescriptor>& sectors_;
+ Options options_;
+
+ bool initialized_;
+
// The last sector that was selected as the "new empty sector" to write to.
// This last new sector is used as the starting point for the next "find a new
// empty sector to write to" operation. By using the last new sector as the
@@ -364,8 +370,6 @@
SectorDescriptor* last_new_sector_;
uint32_t last_transaction_id_;
- bool initialized_ = false;
-
// Working buffer is a general purpose buffer for operations (such as init or
// relocate) to use for working space to remove the need to allocate temporary
// space.