Merge branch 'refactor/nvs_iterator_api' into 'master'

NVS: New interface for iterator functions

Closes IDFGH-6149

See merge request espressif/esp-idf!18081
This commit is contained in:
Jakob Hasse
2022-05-31 07:47:26 +08:00
9 changed files with 322 additions and 131 deletions

View File

@@ -55,11 +55,12 @@ Iterators allow to list key-value pairs stored in NVS, based on specified partit
There are the following functions available:
- :cpp:func:`nvs_entry_find` returns an opaque handle, which is used in subsequent calls to the :cpp:func:`nvs_entry_next` and :cpp:func:`nvs_entry_info` functions.
- :cpp:func:`nvs_entry_next` returns iterator to the next key-value pair.
- :cpp:func:`nvs_entry_find` creates an opaque handle, which is used in subsequent calls to the :cpp:func:`nvs_entry_next` and :cpp:func:`nvs_entry_info` functions.
- :cpp:func:`nvs_entry_next` advances an iterator to the next key-value pair.
- :cpp:func:`nvs_entry_info` returns information about each key-value pair
If none or no other key-value pair was found for given criteria, :cpp:func:`nvs_entry_find` and :cpp:func:`nvs_entry_next` return NULL. In that case, the iterator does not have to be released. If the iterator is no longer needed, you can release it by using the function :cpp:func:`nvs_release_iterator`.
In general, all iterators obtained via :cpp:func:`nvs_entry_find` have to be released using :cpp:func:`nvs_release_iterator`, which also tolerates ``NULL`` iterators.
:cpp:func:`nvs_entry_find` and :cpp:func:`nvs_entry_next` will set the given iterator to ``NULL`` or a valid iterator in all cases except a parameter error occured (i.e., return ``ESP_ERR_NVS_NOT_FOUND``). In case of a parameter error, the given iterator will not be modified. Hence, it is best practice to initialize the iterator to ``NULL`` before calling :cpp:func:`nvs_entry_find` to avoid complicated error checking before releasing the iterator.
Security, tampering, and robustness

View File

@@ -18,3 +18,52 @@ esp_vfs_semihost_register() signature change
--------------------------------------------
New signature is ``esp_err_t esp_vfs_semihost_register(const char* base_path);`` Absolute path as a second parameter will no longer in use. Instead, the OpenOCD command ``ESP_SEMIHOST_BASEDIR`` should be used to set the full path on the host.
NVS
---
``nvs_entry_find()``, ``nvs_entry_next()`` and ``nvs_entry_info()`` always return ``esp_err_t`` now instead of ``void`` or ``nvs_iterator_t``. This provides better error reporting when parameters are invalid or something goes wrong internally than returning ``nullptr`` instead of a valid iterator or checking parameters with ``assert``. ``nvs_entry_find()`` and ``nvs_entry_next()`` modify iterators via parameters now instead of returning an iterator.
The old programming pattern to iterate over an NVS partition was as follows:
.. highlight:: c
::
nvs_iterator_t it = nvs_entry_find(<nvs_partition_name>, <namespace>, 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);
};
The new programming pattern to iterate over an NVS partition is now:
.. highlight:: c
::
nvs_iterator_t it = nullptr;
esp_err_t res = nvs_entry_find(<nvs_partition_name>, <namespace>, 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);
Signature Changes
^^^^^^^^^^^^^^^^^
``nvs_iterator_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type)`` changes to ``esp_err_t nvs_entry_find(const char *part_name, const char *namespace_name, nvs_type_t type, nvs_iterator_t *output_iterator)``. The iterator is returned via the parameter ``output_iterator`` instead of a return value. This allows reporting additional errors, like e.g. memory errors, via the new return value.
``nvs_iterator_t nvs_entry_next(nvs_iterator_t iterator)`` changes to ``esp_err_t nvs_entry_next(nvs_iterator_t *it)``. This allows reporting parameter errors and internal errors, like e.g. flash errors.
``void nvs_entry_info(nvs_iterator_t iterator, nvs_entry_info_t *out_info)`` changes to ``esp_err_t nvs_entry_info(const nvs_iterator_t iterator, nvs_entry_info_t *out_info)`` to allow reporting parameter errors.
Iterator Validity
^^^^^^^^^^^^^^^^^
Note that due to the new signatures, it is possible to have an invalid iterator from ``nvs_entry_find()``, if there is a parameter errors. Hence, it is important to initialize the iterator with ``NULL`` before using ``nvs_entry_find()`` to avoid complex error checking before calling ``nvs_release_iterator()``. A good example is the programming pattern above.

View File

@@ -55,11 +55,12 @@ NVS 迭代器
您可以使用以下函数,执行相关操作:
- ``nvs_entry_find``返回一个不透明句柄,用于后续调用 ``nvs_entry_next````nvs_entry_info`` 函数;
- ``nvs_entry_next``返回指向下一个键值对的迭代器
- ``nvs_entry_find``创建一个不透明句柄,用于后续调用 ``nvs_entry_next````nvs_entry_info`` 函数;
- ``nvs_entry_next``让迭代器指向下一个键值对;
- ``nvs_entry_info``:返回每个键值对的信息。
如果未找到符合标准的键值对,``nvs_entry_find````nvs_entry_next`` 将返回 NULL此时不必释放迭代器。若不再需要迭代器可使用 ``nvs_release_iterator`` 释放迭代器
总的来说,所有通过 :cpp:func:`nvs_entry_find` 获得的迭代器(包括 ``NULL`` 迭代器)都必须使用 :cpp:func:`nvs_release_iterator` 释放。
一般情况下,:cpp:func:`nvs_entry_find`:cpp:func:`nvs_entry_next` 会将给定的迭代器设置为 ``NULL`` 或为一个有效的迭代器。但如果出现参数错误(如返回 ``ESP_ERR_NVS_NOT_FOUND``),给定的迭代器不会被修改。因此,在调用 :cpp:func:`nvs_entry_find` 之前最好将迭代器初始化为 ``NULL``,这样可以避免在释放迭代器之前进行复杂的错误检查。
安全性、篡改性及鲁棒性
@@ -168,7 +169,7 @@ ESP-IDF :example:`storage` 目录下提供了数个代码示例:
:example:`storage/nvs_rw_blob` 
演示如何读取及写入 NVS 单个整数值和 Blob(二进制大对象),并在 NVS 中存储这一数值,即便 {IDF_TARGET_NAME} 模组重启也不会消失。
演示如何读取及写入 NVS 单个整数值和 BLOB(二进制大对象),并在 NVS 中存储这一数值,即便 {IDF_TARGET_NAME} 模组重启也不会消失。
* value - 记录 {IDF_TARGET_NAME} 模组软重启次数和硬重启次数。
* blob - 内含记录模组运行次数的表格。此表格将被从 NVS 读取至动态分配的 RAM 上。每次手动软重启后,表格内运行次数即增加一次,新加的运行次数被写入 NVS。下拉 GPIO0 即可手动软重启。
@@ -177,7 +178,7 @@ ESP-IDF :example:`storage` 目录下提供了数个代码示例:
:example:`storage/nvs_rw_value_cxx`
这个例子与 :example:`storage/nvs_rw_value` 完全一样,只是使用了 C++ 的 NVS 处理类。
这个例子与 :example:`storage/nvs_rw_value` 完全一样,只是使用了 C++ 的 NVS 句柄类。
内部实现
---------