Skip to content

Commit

Permalink
Merge branch 'feature/storage_nvs_find_key' into 'master'
Browse files Browse the repository at this point in the history
feat(nvs_flash): Added function nvs_find_key

Closes IDFGH-10963

See merge request espressif/esp-idf!26498
  • Loading branch information
rrtandler committed Dec 8, 2023
2 parents c008a51 + 8740888 commit cb66d6f
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 28 deletions.
85 changes: 85 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 @@ -3310,7 +3310,92 @@ TEST_CASE("nvs multiple write with same key but different types", "[nvs][xxx]")
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}

TEST_CASE("nvs find key tests", "[nvs]")
{
const size_t buff_len = 4096;

PartitionEmulationFixture f(0, 20);
f.randomize(100);

nvs_handle_t handle_1;
nvs_handle_t handle_2;

const uint32_t NVS_FLASH_SECTOR = 6;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 13;


TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
f.erase(i);
}
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
NVS_FLASH_SECTOR,
NVS_FLASH_SECTOR_COUNT_MIN));

nvs_type_t datatype_found; // datatype of entry found

// open writeable namespace
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));

// set value, erease value, test find before and after each of steps
TEST_ESP_ERR(nvs_find_key(handle_1, "foo", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
// write "foo" as I32, should find it, first attempt without pointer to type variable
TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
TEST_ESP_OK(nvs_find_key(handle_1, "foo", nullptr));
// second search attempt with pointer to type variable specified
TEST_ESP_OK(nvs_find_key(handle_1, "foo", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I32);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo", &datatype_found), ESP_ERR_NVS_NOT_FOUND);

// set value, rewrite value, erease value, test find before and after each of steps
TEST_ESP_ERR(nvs_find_key(handle_1, "foo1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_1, "foo1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foo1", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I16);
TEST_ESP_OK(nvs_set_i16(handle_1, "foo1", 0x4321));
TEST_ESP_OK(nvs_find_key(handle_1, "foo1", &datatype_found));
CHECK(datatype_found == NVS_TYPE_I16);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);

// set blob value, rewrite blob, delete blob, test find before and after each of steps
uint8_t *p_buff = (uint8_t *) malloc(buff_len);
CHECK(p_buff != nullptr);
TEST_ESP_ERR(nvs_find_key(handle_1, "foo2", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
for(size_t i=0; i<buff_len; i++) p_buff[i] = (uint8_t) (i%0xff);
TEST_ESP_OK(nvs_set_blob(handle_1, "foo2", p_buff, buff_len));
TEST_ESP_OK(nvs_find_key(handle_1, "foo2", &datatype_found));
CHECK(datatype_found == NVS_TYPE_BLOB);
for(size_t i=0; i<buff_len; i++) p_buff[i] = (uint8_t) ((buff_len-i-1)%0xff);
TEST_ESP_OK(nvs_set_blob(handle_1, "foo2", p_buff, buff_len));
TEST_ESP_OK(nvs_find_key(handle_1, "foo2", &datatype_found));
CHECK(datatype_found == NVS_TYPE_BLOB);
TEST_ESP_OK(nvs_erase_key(handle_1, "foo2"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foo2", &datatype_found), ESP_ERR_NVS_NOT_FOUND);

// test namespace is respected in nvs_find_key
// open second writeable namespace
TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_1, "foon1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foon1", &datatype_found));
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_set_i16(handle_2, "foon1", 0x1234));
TEST_ESP_OK(nvs_find_key(handle_1, "foon1", &datatype_found));
TEST_ESP_OK(nvs_find_key(handle_2, "foon1", &datatype_found));
TEST_ESP_OK(nvs_erase_key(handle_1, "foon1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_find_key(handle_2, "foon1", &datatype_found));
TEST_ESP_OK(nvs_erase_key(handle_2, "foon1"));
TEST_ESP_ERR(nvs_find_key(handle_1, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_ERR(nvs_find_key(handle_2, "foon1", &datatype_found), ESP_ERR_NVS_NOT_FOUND);

nvs_close(handle_1);
nvs_close(handle_2);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
/* Add new tests above */
/* This test has to be the final one */

Expand Down
19 changes: 19 additions & 0 deletions components/nvs_flash/include/nvs.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,25 @@ esp_err_t nvs_get_str (nvs_handle_t handle, const char* key, char* out_value, si
esp_err_t nvs_get_blob(nvs_handle_t handle, const char* key, void* out_value, size_t* length);
/**@}*/

/**
* @brief Lookup key-value pair with given key name.
*
* Note that function may indicate both existence of the key as well as the data type of NVS entry if it is found.
*
* @param[in] handle Storage handle obtained with nvs_open.
* @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
* @param[out] out_type Pointer to the output variable populated with data type of NVS entry in case key was found.
* May be NULL, respective data type is then not provided.
* @return
* - ESP_OK if NVS entry for key provided was found
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_find_key(nvs_handle_t handle, const char* key, nvs_type_t* out_type);

/**
* @brief Erase key-value pair with given key name.
*
Expand Down
15 changes: 15 additions & 0 deletions components/nvs_flash/include/nvs_handle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,21 @@ class NVSHandle {
*/
virtual esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) = 0;

/**
* @brief Checks whether key exists and optionally returns also data type of associated entry.
*
* @param[in] key Key name. Maximum length is (NVS_KEY_NAME_MAX_SIZE-1) characters. Shouldn't be empty.
* @param[out] nvstype Nvs data type to of entry, if it exists.
*
* @return - ESP_OK if NVS entry for key provided was found. Data type will be returned via \c nvstype.
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist.
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL.
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled).
* - other error codes from the underlying storage driver.
*/
virtual esp_err_t find_key(const char* key, nvs_type_t &nvstype) = 0;

/**
* @brief Erases an entry.
*/
Expand Down
19 changes: 19 additions & 0 deletions components/nvs_flash/src/nvs_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,25 @@ extern "C" void nvs_close(nvs_handle_t handle)
delete static_cast<NVSHandleEntry*>(it);
}

extern "C" esp_err_t nvs_find_key(nvs_handle_t c_handle, const char* key, nvs_type_t* out_type)
{
Lock lock;
ESP_LOGD(TAG, "%s %s", __func__, key);
NVSHandleSimple *handle;
auto err = nvs_find_ns_handle(c_handle, &handle);
if (err != ESP_OK) {
return err;
}

nvs_type_t nvstype;
err = handle->find_key(key, nvstype);

if(err == ESP_OK && out_type != nullptr)
*out_type = nvstype;

return err;
}

extern "C" esp_err_t nvs_erase_key(nvs_handle_t c_handle, const char* key)
{
Lock lock;
Expand Down
24 changes: 11 additions & 13 deletions components/nvs_flash/src/nvs_handle_locked.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 "nvs_handle_locked.hpp"

namespace nvs {
Expand Down Expand Up @@ -47,6 +39,12 @@ esp_err_t NVSHandleLocked::get_item_size(ItemType datatype, const char *key, siz
return handle->get_item_size(datatype, key, size);
}

esp_err_t NVSHandleLocked::find_key(const char* key, nvs_type_t &nvstype)
{
Lock lock;
return handle->find_key(key, nvstype);
}

esp_err_t NVSHandleLocked::erase_item(const char* key) {
Lock lock;
return handle->erase_item(key);
Expand Down
20 changes: 7 additions & 13 deletions components/nvs_flash/src/nvs_handle_locked.hpp
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
*/
#ifndef NVS_HANDLE_LOCKED_HPP_
#define NVS_HANDLE_LOCKED_HPP_

Expand Down Expand Up @@ -49,6 +41,8 @@ class NVSHandleLocked : public NVSHandle {

esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;

esp_err_t find_key(const char* key, nvs_type_t &nvstype) override;

esp_err_t erase_item(const char* key) override;

esp_err_t erase_all() override;
Expand Down
17 changes: 17 additions & 0 deletions components/nvs_flash/src/nvs_handle_simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ esp_err_t NVSHandleSimple::get_item_size(ItemType datatype, const char *key, siz
return mStoragePtr->getItemDataSize(mNsIndex, datatype, key, size);
}

esp_err_t NVSHandleSimple::find_key(const char* key, nvs_type_t &nvstype)
{
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;

nvs::ItemType datatype;
esp_err_t err = mStoragePtr->findKey(mNsIndex, key, &datatype);
if(err != ESP_OK)
return err;

if(datatype == ItemType::BLOB_IDX || datatype == ItemType::BLOB)
datatype = ItemType::BLOB_DATA;

nvstype = (nvs_type_t) datatype;

return err;
}

esp_err_t NVSHandleSimple::erase_item(const char* key)
{
if (!valid) return ESP_ERR_NVS_INVALID_HANDLE;
Expand Down
2 changes: 2 additions & 0 deletions components/nvs_flash/src/nvs_handle_simple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class NVSHandleSimple : public intrusive_list_node<NVSHandleSimple>,

esp_err_t get_item_size(ItemType datatype, const char *key, size_t &size) override;

esp_err_t find_key(const char *key, nvs_type_t &nvstype) override;

esp_err_t erase_item(const char *key) override;

esp_err_t erase_all() override;
Expand Down
20 changes: 20 additions & 0 deletions components/nvs_flash/src/nvs_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,26 @@ esp_err_t Storage::eraseNamespace(uint8_t nsIndex)

}

esp_err_t Storage::findKey(const uint8_t nsIndex, const char* key, ItemType* datatype)
{
if (mState != StorageState::ACTIVE) {
return ESP_ERR_NVS_NOT_INITIALIZED;
}

Item item;
Page* findPage = nullptr;
auto err = findItem(nsIndex, ItemType::ANY, key, findPage, item);
if (err != ESP_OK) {
return err;
}

if(datatype != nullptr) {
*datatype = item.datatype;
}

return err;
}

esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize)
{
if (mState != StorageState::ACTIVE) {
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 @@ -71,6 +71,8 @@ class Storage : public intrusive_list_node<Storage>, public ExceptionlessAllocat

esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize);

esp_err_t findKey(const uint8_t nsIndex, const char* key, ItemType* datatype);

esp_err_t getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize);

esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key);
Expand Down
2 changes: 0 additions & 2 deletions tools/ci/check_copyright_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,6 @@ components/mbedtls/port/sha/parallel_engine/sha.c
components/nvs_flash/include/nvs_handle.hpp
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_item_hash_list.cpp
components/nvs_flash/src/nvs_pagemanager.hpp
components/nvs_flash/src/nvs_partition_lookup.cpp
Expand Down

0 comments on commit cb66d6f

Please sign in to comment.