Merge branch 'contrib/github_pr_11118' into 'master'

nvs: support iteration over namespace by handle (GitHub PR)

Closes IDFGH-9782

See merge request espressif/esp-idf!23175
This commit is contained in:
Radek Tandler 2023-08-31 20:59:19 +08:00
commit 352e759d1d
8 changed files with 140 additions and 20 deletions

View File

@ -761,6 +761,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);
}
@ -805,6 +820,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));

View File

@ -675,14 +675,53 @@ 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 handle (which defines a partition and namespace)
* nvs_iterator_t it = NULL;
* esp_err_t res = nvs_entry_find_in_handle(<nvs_handle>, NVS_TYPE_ANY, &it);
* while(res == ESP_OK) {
* nvs_entry_info_t info;
* nvs_entry_info(it, &info); // Can omit error check if parameters are guaranteed to be non-NULL
* printf("key '%s', type '%d' \n", info.key, info.type);
* res = nvs_entry_next(&it);
* }
* nvs_release_iterator(it);
* \endcode
*
* @param[in] handle Handle obtained from nvs_open function.
*
* @param[in] type One of nvs_type_t values.
*
* @param[out] output_iterator
* Set to a valid iterator to enumerate all the entries found.
* Set to NULL if no entry for specified criteria was found.
* If any other error except ESP_ERR_INVALID_ARG occurs, \c output_iterator is NULL, too.
* If ESP_ERR_INVALID_ARG occurs, \c output_iterator is not changed.
* If a valid iterator is obtained through this function, it has to be released
* using \c nvs_release_iterator when not used any more, unless ESP_ERR_INVALID_ARG is returned.
*
* @return
* - ESP_OK if no internal error or programming error occurred.
* - ESP_ERR_NVS_NOT_FOUND if no element of specified criteria has been found.
* - ESP_ERR_NO_MEM if memory has been exhausted during allocation of internal structures.
* - ESP_ERR_NVS_INVALID_HANDLE if unknown handle was specified.
* - ESP_ERR_INVALID_ARG if output_iterator parameter is NULL.
* Note: don't release \c output_iterator in case ESP_ERR_INVALID_ARG has been returned
*/
esp_err_t nvs_entry_find_in_handle(nvs_handle_t 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.
@ -695,7 +734,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.
*
@ -708,7 +748,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);

View File

@ -786,6 +786,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 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_obj;
auto err = nvs_find_ns_handle(handle, &handle_obj);
if (err != ESP_OK) {
*output_iterator = nullptr;
return err;
}
pStorage = handle_obj->get_storage();
nvs_iterator_t it = create_iterator(pStorage, type);
if (it == nullptr) {
*output_iterator = nullptr;
return ESP_ERR_NO_MEM;
}
bool entryFound = handle_obj->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) {

View File

@ -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"
@ -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);
}
@ -134,4 +130,8 @@ const char *NVSHandleSimple::get_partition_name() const {
return mStoragePtr->getPartName();
}
Storage *NVSHandleSimple::get_storage() const {
return mStoragePtr;
}
}

View File

@ -69,10 +69,14 @@ public:
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.

View File

@ -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 &&

View File

@ -125,7 +125,9 @@ public:
esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries);
bool findEntry(nvs_opaque_iterator_t*, const char* name);
bool findEntry(nvs_opaque_iterator_t* it, const char* name);
bool findEntryNs(nvs_opaque_iterator_t* it, uint8_t nsIndex);
bool nextEntry(nvs_opaque_iterator_t* it);

View File

@ -596,7 +596,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