Skip to content

Commit

Permalink
nvs: support iteration over namespace by index
Browse files Browse the repository at this point in the history
Users of the nvs API are likely to have `nvs_handle_t` in all cases, but
not all of them carry around the partition name and namespace name (as
they aren't needed after creating an `nvs_handle_t`).

Allow this common case to use nvs iteration without them tracking
additional data by using the `nvs_handle_t` to locate the namespace
index and the partition name by introducing an alterate to
`nvs_entry_find` called `nvs_entry_find_in_handle`, which operates
similarly except that it is given a `nvs_handle_t` instead of partition
and namespace strings.

This is somewhat more limited than the `nvs_entry_find` API as one
cannot examine all keys in a given partition.
  • Loading branch information
codysch committed Apr 3, 2023
1 parent 42261df commit 0dc4e8a
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 19 deletions.
24 changes: 24 additions & 0 deletions components/nvs_flash/host_test/nvs_host_test/main/test_nvs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,21 @@ TEST_CASE("nvs iterators tests", "[nvs]")
return count;
};

auto entry_count_handle = [](nvs_handle_t handle, nvs_type_t type)-> int {
int count = 0;
nvs_iterator_t it = nullptr;
esp_err_t res = nvs_entry_find_in_handle(handle, type, &it);
for (count = 0; res == ESP_OK; count++)
{
res = nvs_entry_next(&it);
}
CHECK(res == ESP_ERR_NVS_NOT_FOUND); // after finishing the loop or if no entry was found to begin with,
// res has to be ESP_ERR_NVS_NOT_FOUND or some internal error
// or programming error occurred
nvs_release_iterator(it); // unneccessary call but emphasizes the programming pattern
return count;
};

SECTION("No partition found return ESP_ERR_NVS_NOT_FOUND") {
CHECK(nvs_entry_find("", NULL, NVS_TYPE_ANY, &it) == ESP_ERR_NVS_NOT_FOUND);
}
Expand Down Expand Up @@ -803,6 +818,15 @@ TEST_CASE("nvs iterators tests", "[nvs]")
CHECK(entry_count(NVS_DEFAULT_PART_NAME, NULL, NVS_TYPE_U64) == 1);
}


SECTION("Number of entries found for specified handle and type is correct") {
CHECK(entry_count_handle(handle_1, NVS_TYPE_ANY) == 11);
CHECK(entry_count_handle(handle_1, NVS_TYPE_I32) == 3);
CHECK(entry_count_handle(handle_2, NVS_TYPE_ANY) == 4);
CHECK(entry_count_handle(handle_2, NVS_TYPE_I32) == 2);
CHECK(entry_count_handle(handle_2, NVS_TYPE_U64) == 1);
}

SECTION("New entry is not created when existing key-value pair is set") {
CHECK(entry_count(NVS_DEFAULT_PART_NAME, name_2, NVS_TYPE_ANY) == 4);
TEST_ESP_OK(nvs_set_i32(handle_2, "value1", -222));
Expand Down
43 changes: 38 additions & 5 deletions components/nvs_flash/include/nvs.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,14 +661,44 @@ esp_err_t nvs_entry_find(const char *part_name,
nvs_type_t type,
nvs_iterator_t *output_iterator);

/**
* @brief Create an iterator to enumerate NVS entries based on a handle and type
*
* \code{c}
* // Example of listing all the key-value pairs of any type under specified partition and namespace
* nvs_iterator_t it = nvs_entry_find_in_handle(handle, NVS_TYPE_ANY);
* while (it != NULL) {
* nvs_entry_info_t info;
* nvs_entry_info(it, &info);
* it = nvs_entry_next(it);
* printf("key '%s', type '%d' \n", info.key, info.type);
* };
* // Note: no need to release iterator obtained from nvs_entry_find_in_handle function when
* // nvs_entry_find_in_handle or nvs_entry_next function return NULL, indicating no other
* // element for specified criteria was found.
* }
* \endcode
*
* @param[in] handle Handle obtained from nvs_open function.
*
* @param[in] type One of nvs_type_t values.
*
* @return
* Iterator used to enumerate all the entries found, or NULL if no entry satisfying
* criteria was found. Iterator obtained through this function has to be released using
* nvs_release_iterator when not used any more.
*/
esp_err_t nvs_entry_find_in_handle(nvs_handle_t c_handle, nvs_type_t type, nvs_iterator_t *output_iterator);

/**
* @brief Advances the iterator to next item matching the iterator criteria.
*
* Note that any copies of the iterator will be invalid after this call.
*
* @param[inout] iterator Iterator obtained from nvs_entry_find function. Must be non-NULL.
* If any error except ESP_ERR_INVALID_ARG occurs, \c iterator is set to NULL.
* If ESP_ERR_INVALID_ARG occurs, \c iterator is not changed.
* @param[inout] iterator Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle
* function. Must be non-NULL. If any error except ESP_ERR_INVALID_ARG
* occurs, \c iterator is set to NULL. If ESP_ERR_INVALID_ARG occurs, \c
* iterator is not changed.
*
* @return
* - ESP_OK if no internal error or programming error occurred.
Expand All @@ -681,7 +711,8 @@ esp_err_t nvs_entry_next(nvs_iterator_t *iterator);
/**
* @brief Fills nvs_entry_info_t structure with information about entry pointed to by the iterator.
*
* @param[in] iterator Iterator obtained from nvs_entry_find function. Must be non-NULL.
* @param[in] iterator Iterator obtained from nvs_entry_find or nvs_entry_find_in_handle
* function. Must be non-NULL.
*
* @param[out] out_info Structure to which entry information is copied.
*
Expand All @@ -694,7 +725,9 @@ esp_err_t nvs_entry_info(const nvs_iterator_t iterator, nvs_entry_info_t *out_in
/**
* @brief Release iterator
*
* @param[in] iterator Release iterator obtained from nvs_entry_find function. NULL argument is allowed.
* @param[in] iterator Release iterator obtained from nvs_entry_find or
* nvs_entry_find_in_handle or nvs_entry_next function. NULL argument is
* allowed.
*
*/
void nvs_release_iterator(nvs_iterator_t iterator);
Expand Down
40 changes: 40 additions & 0 deletions components/nvs_flash/src/nvs_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,46 @@ extern "C" esp_err_t nvs_entry_find(const char *part_name, const char *namespace
return ESP_OK;
}

extern "C" esp_err_t nvs_entry_find_in_handle(nvs_handle_t c_handle, nvs_type_t type, nvs_iterator_t *output_iterator)
{
if (output_iterator == nullptr) {
return ESP_ERR_INVALID_ARG;
}

esp_err_t lock_result = Lock::init();
if (lock_result != ESP_OK) {
*output_iterator = nullptr;
return lock_result;
}

Lock lock;
nvs::Storage *pStorage;
NVSHandleSimple *handle;

auto err = nvs_find_ns_handle(c_handle, &handle);
if (err != ESP_OK) {
*output_iterator = nullptr;
return err;
}

pStorage = handle->get_storage();
nvs_iterator_t it = create_iterator(pStorage, type);
if (it == nullptr) {
*output_iterator = nullptr;
return ESP_ERR_NO_MEM;
}

bool entryFound = handle->findEntryNs(it);
if (!entryFound) {
free(it);
*output_iterator = nullptr;
return ESP_ERR_NVS_NOT_FOUND;
}

*output_iterator = it;
return ESP_OK;
}

extern "C" esp_err_t nvs_entry_next(nvs_iterator_t *iterator)
{
if (iterator == nullptr) {
Expand Down
26 changes: 13 additions & 13 deletions components/nvs_flash/src/nvs_handle_simple.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// 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

// http://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.
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <cstdlib>
#include "nvs_handle.hpp"
#include "nvs_partition_manager.hpp"
Expand Down Expand Up @@ -126,6 +118,10 @@ bool NVSHandleSimple::findEntry(nvs_opaque_iterator_t* it, const char* name) {
return mStoragePtr->findEntry(it, name);
}

bool NVSHandleSimple::findEntryNs(nvs_opaque_iterator_t* it) {
return mStoragePtr->findEntryNs(it, mNsIndex);
}

bool NVSHandleSimple::nextEntry(nvs_opaque_iterator_t* it) {
return mStoragePtr->nextEntry(it);
}
Expand All @@ -134,4 +130,8 @@ const char *NVSHandleSimple::get_partition_name() const {
return mStoragePtr->getPartName();
}

Storage *NVSHandleSimple::get_storage() const {
return mStoragePtr;
}

}
4 changes: 4 additions & 0 deletions components/nvs_flash/src/nvs_handle_simple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@ class NVSHandleSimple : public intrusive_list_node<NVSHandleSimple>,

bool findEntry(nvs_opaque_iterator_t *it, const char *name);

bool findEntryNs(nvs_opaque_iterator_t *it);

bool nextEntry(nvs_opaque_iterator_t *it);

const char *get_partition_name() const;

Storage *get_storage() const;

private:
/**
* The underlying storage's object.
Expand Down
9 changes: 9 additions & 0 deletions components/nvs_flash/src/nvs_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,15 @@ bool Storage::findEntry(nvs_opaque_iterator_t* it, const char* namespace_name)
return nextEntry(it);
}

bool Storage::findEntryNs(nvs_opaque_iterator_t* it, uint8_t nsIndex)
{
it->entryIndex = 0;
it->nsIndex = nsIndex;
it->page = mPageManager.begin();

return nextEntry(it);
}

inline bool isIterableItem(Item& item)
{
return (item.nsIndex != 0 &&
Expand Down
2 changes: 2 additions & 0 deletions components/nvs_flash/src/nvs_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ class Storage : public intrusive_list_node<Storage>, public ExceptionlessAllocat

bool findEntry(nvs_opaque_iterator_t*, const char* name);

bool findEntryNs(nvs_opaque_iterator_t*, uint8_t nsIndex);

bool nextEntry(nvs_opaque_iterator_t* it);

protected:
Expand Down
1 change: 0 additions & 1 deletion tools/ci/check_copyright_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,6 @@ components/nvs_flash/src/nvs_cxx_api.cpp
components/nvs_flash/src/nvs_encrypted_partition.hpp
components/nvs_flash/src/nvs_handle_locked.cpp
components/nvs_flash/src/nvs_handle_locked.hpp
components/nvs_flash/src/nvs_handle_simple.cpp
components/nvs_flash/src/nvs_item_hash_list.cpp
components/nvs_flash/src/nvs_pagemanager.hpp
components/nvs_flash/src/nvs_partition.cpp
Expand Down

0 comments on commit 0dc4e8a

Please sign in to comment.