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.