nvs:Add functions for calculating used/free entries

Users needs functions to count the number of free and used entries.

1. `nvs_get_stats()` This function return structure of statistic about the uspace NVS.
(Struct: used_entries, free_entries, total_entries and namespace_count)
2. `nvs_get_used_entry_count()` The second function return amount of entries in the namespace (by handler)
3. Added unit tests.

Closes TW<12282>
This commit is contained in:
konstantin 2018-02-20 12:11:56 +05:00 committed by Konstantin Kondrashov
parent bdadd95dd7
commit c93626db3f
10 changed files with 505 additions and 4 deletions

View file

@ -356,6 +356,88 @@ esp_err_t nvs_commit(nvs_handle handle);
*/
void nvs_close(nvs_handle handle);
/**
* @note Info about storage space NVS.
*/
typedef struct {
size_t used_entries; /**< Amount of used entries. */
size_t free_entries; /**< Amount of free entries. */
size_t total_entries; /**< Amount all available entries. */
size_t namespace_count; /**< Amount name space. */
} nvs_stats_t;
/**
* @brief Fill structure nvs_stats_t. It provides info about used memory the partition.
*
* This function calculates to runtime the number of used entries, free entries, total entries,
* and amount namespace in partition.
*
* \code{c}
* // Example of nvs_get_stats() to get the number of used entries and free entries:
* nvs_stats_t nvs_stats;
* nvs_get_stats(NULL, &nvs_stats);
* printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d)\n",
nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries);
* \endcode
*
* @param[in] part_name Partition name NVS in the partition table.
* If pass a NULL than will use NVS_DEFAULT_PART_NAME ("nvs").
*
* @param[out] nvs_stats Returns filled structure nvs_states_t.
* It provides info about used memory the partition.
*
*
* @return
* - ESP_OK if the changes have been written successfully.
* Return param nvs_stats will be filled.
* - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "name" is not found.
* Return param nvs_stats will be filled 0.
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized.
* Return param nvs_stats will be filled 0.
* - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL.
* - ESP_ERR_INVALID_STATE if there is page with the status of INVALID.
* Return param nvs_stats will be filled not with correct values because
* not all pages will be counted. Counting will be interrupted at the first INVALID page.
*/
esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats);
/**
* @brief Calculate all entries in a namespace.
*
* Note that to find out the total number of records occupied by the namespace,
* add one to the returned value used_entries (if err is equal to ESP_OK).
* Because the name space entry takes one entry.
*
* \code{c}
* // Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace:
* nvs_handle handle;
* nvs_open("namespace1", NVS_READWRITE, &handle);
* ...
* size_t used_entries;
* size_t total_entries_namespace;
* if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){
* // the total number of records occupied by the namespace
* total_entries_namespace = used_entries + 1;
* }
* \endcode
*
* @param[in] handle Handle obtained from nvs_open function.
*
* @param[out] used_entries Returns amount of used entries from a namespace.
*
*
* @return
* - ESP_OK if the changes have been written successfully.
* Return param used_entries will be filled valid value.
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized.
* Return param used_entries will be filled 0.
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL.
* Return param used_entries will be filled 0.
* - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL.
* - Other error codes from the underlying storage driver.
* Return param used_entries will be filled 0.
*/
esp_err_t nvs_get_used_entry_count(nvs_handle handle, size_t* used_entries);
#ifdef __cplusplus
} // extern "C"

View file

@ -458,3 +458,49 @@ extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_
return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length);
}
extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats)
{
Lock lock;
nvs::Storage* pStorage;
if (nvs_stats == NULL) {
return ESP_ERR_INVALID_ARG;
}
nvs_stats->used_entries = 0;
nvs_stats->free_entries = 0;
nvs_stats->total_entries = 0;
nvs_stats->namespace_count = 0;
pStorage = lookup_storage_from_name((part_name == NULL) ? NVS_DEFAULT_PART_NAME : part_name);
if (pStorage == NULL) {
return ESP_ERR_NVS_PART_NOT_FOUND;
}
if(!pStorage->isValid()){
return ESP_ERR_NVS_NOT_INITIALIZED;
}
return pStorage->fillStats(*nvs_stats);
}
extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle handle, size_t* used_entries)
{
Lock lock;
if(used_entries == NULL){
return ESP_ERR_INVALID_ARG;
}
*used_entries = 0;
HandleEntry entry;
auto err = nvs_find_ns_handle(handle, entry);
if (err != ESP_OK) {
return err;
}
size_t used_entry_count;
err = entry.mStoragePtr->calcEntriesInNamespace(entry.mNsIndex, used_entry_count);
if(err == ESP_OK){
*used_entries = used_entry_count;
}
return err;
}

View file

@ -862,4 +862,33 @@ void Page::debugDump() const
}
}
esp_err_t Page::calcEntries(nvs_stats_t &nvsStats)
{
assert(mState != PageState::FREEING);
nvsStats.total_entries += ENTRY_COUNT;
switch (mState) {
case PageState::UNINITIALIZED:
case PageState::CORRUPT:
nvsStats.free_entries += ENTRY_COUNT;
break;
case PageState::FULL:
case PageState::ACTIVE:
nvsStats.used_entries += mUsedEntryCount;
nvsStats.free_entries += ENTRY_COUNT - mUsedEntryCount; // it's equivalent free + erase entries.
break;
case PageState::INVALID:
return ESP_ERR_INVALID_STATE;
break;
default:
assert(false && "Unhandled state");
break;
}
return ESP_OK;
}
} // namespace nvs

View file

@ -133,6 +133,8 @@ public:
void debugDump() const;
esp_err_t calcEntries(nvs_stats_t &nvsStats);
protected:
class Header

View file

@ -197,4 +197,26 @@ esp_err_t PageManager::activatePage()
return ESP_OK;
}
esp_err_t PageManager::fillStats(nvs_stats_t& nvsStats)
{
nvsStats.used_entries = 0;
nvsStats.free_entries = 0;
nvsStats.total_entries = 0;
esp_err_t err = ESP_OK;
// list of used pages
for (auto p = mPageList.begin(); p != mPageList.end(); ++p) {
err = p->calcEntries(nvsStats);
if (err != ESP_OK) {
return err;
}
}
// free pages
nvsStats.total_entries += mFreePageList.size() * Page::ENTRY_COUNT;
nvsStats.free_entries += mFreePageList.size() * Page::ENTRY_COUNT;
return err;
}
} // namespace nvs

View file

@ -50,6 +50,8 @@ public:
esp_err_t requestNewPage();
esp_err_t fillStats(nvs_stats_t& nvsStats);
protected:
friend class Iterator;

View file

@ -291,4 +291,37 @@ void Storage::debugCheck()
}
#endif //ESP_PLATFORM
esp_err_t Storage::fillStats(nvs_stats_t& nvsStats)
{
nvsStats.namespace_count = mNamespaces.size();
return mPageManager.fillStats(nvsStats);
}
esp_err_t Storage::calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries)
{
usedEntries = 0;
if (mState != StorageState::ACTIVE) {
return ESP_ERR_NVS_NOT_INITIALIZED;
}
for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) {
size_t itemIndex = 0;
Item item;
while (true) {
auto err = it->findItem(nsIndex, ItemType::ANY, nullptr, itemIndex, item);
if (err == ESP_ERR_NVS_NOT_FOUND) {
break;
}
else if (err != ESP_OK) {
return err;
}
usedEntries += item.span;
itemIndex += item.span;
if(itemIndex >= it->ENTRY_COUNT) break;
}
}
return ESP_OK;
}
}

View file

@ -89,6 +89,9 @@ public:
void debugCheck();
esp_err_t fillStats(nvs_stats_t& nvsStats);
esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries);
protected:

View file

@ -65,3 +65,151 @@ TEST_CASE("various nvs tests", "[nvs]")
nvs_close(handle_2);
}
TEST_CASE("calculate used and free space", "[nvs]")
{
TEST_ESP_ERR(nvs_get_stats(NULL, NULL), ESP_ERR_INVALID_ARG);
nvs_stats_t stat1;
nvs_stats_t stat2;
TEST_ESP_ERR(nvs_get_stats(NULL, &stat1), ESP_ERR_NVS_PART_NOT_FOUND);
TEST_ASSERT_TRUE(stat1.free_entries == 0);
TEST_ASSERT_TRUE(stat1.namespace_count == 0);
TEST_ASSERT_TRUE(stat1.total_entries == 0);
TEST_ASSERT_TRUE(stat1.used_entries == 0);
nvs_handle handle = 0;
size_t h_count_entries;
TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
TEST_ASSERT_TRUE(h_count_entries == 0);
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err);
const esp_partition_t* nvs_partition = esp_partition_find_first(
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
assert(nvs_partition && "partition table must have an NVS partition");
ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) );
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
// erase if have any namespace
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
if(stat1.namespace_count != 0) {
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_deinit());
TEST_ESP_OK(nvs_flash_init());
}
// after erase. empty partition
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
TEST_ASSERT_TRUE(stat1.free_entries != 0);
TEST_ASSERT_TRUE(stat1.namespace_count == 0);
TEST_ASSERT_TRUE(stat1.total_entries != 0);
TEST_ASSERT_TRUE(stat1.used_entries == 0);
// create namespace test_k1
nvs_handle handle_1;
TEST_ESP_OK(nvs_open("test_k1", NVS_READWRITE, &handle_1));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries);
TEST_ASSERT_TRUE(stat2.namespace_count == 1);
TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries);
TEST_ASSERT_TRUE(stat2.used_entries == 1);
// create pair key-value com
TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x12345678));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
TEST_ASSERT_TRUE(stat1.free_entries + 1 == stat2.free_entries);
TEST_ASSERT_TRUE(stat1.namespace_count == 1);
TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries);
TEST_ASSERT_TRUE(stat1.used_entries == 2);
// change value in com
TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x01234567));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
TEST_ASSERT_TRUE(stat2.free_entries == stat1.free_entries);
TEST_ASSERT_TRUE(stat2.namespace_count == 1);
TEST_ASSERT_TRUE(stat2.total_entries != 0);
TEST_ASSERT_TRUE(stat2.used_entries == 2);
// create pair key-value ru
TEST_ESP_OK(nvs_set_i32(handle_1, "ru", 0x00FF00FF));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
TEST_ASSERT_TRUE(stat1.free_entries + 1 == stat2.free_entries);
TEST_ASSERT_TRUE(stat1.namespace_count == 1);
TEST_ASSERT_TRUE(stat1.total_entries != 0);
TEST_ASSERT_TRUE(stat1.used_entries == 3);
// amount valid pair in namespace 1
size_t h1_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_1, &h1_count_entries));
TEST_ASSERT_TRUE(h1_count_entries == 2);
nvs_handle handle_2;
// create namespace test_k2
TEST_ESP_OK(nvs_open("test_k2", NVS_READWRITE, &handle_2));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries);
TEST_ASSERT_TRUE(stat2.namespace_count == 2);
TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries);
TEST_ASSERT_TRUE(stat2.used_entries == 4);
// create pair key-value
TEST_ESP_OK(nvs_set_i32(handle_2, "su1", 0x00000001));
TEST_ESP_OK(nvs_set_i32(handle_2, "su2", 0x00000002));
TEST_ESP_OK(nvs_set_i32(handle_2, "sus", 0x00000003));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
TEST_ASSERT_TRUE(stat1.free_entries + 3 == stat2.free_entries);
TEST_ASSERT_TRUE(stat1.namespace_count == 2);
TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries);
TEST_ASSERT_TRUE(stat1.used_entries == 7);
TEST_ASSERT_TRUE(stat1.total_entries == (stat1.used_entries + stat1.free_entries));
// amount valid pair in namespace 2
size_t h2_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_2, &h2_count_entries));
TEST_ASSERT_TRUE(h2_count_entries == 3);
TEST_ASSERT_TRUE(stat1.used_entries == (h1_count_entries + h2_count_entries + stat1.namespace_count));
nvs_close(handle_1);
nvs_close(handle_2);
size_t temp = h2_count_entries;
TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, &h2_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
TEST_ASSERT_TRUE(h2_count_entries == 0);
h2_count_entries = temp;
TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, NULL), ESP_ERR_INVALID_ARG);
nvs_handle handle_3;
// create namespace test_k3
TEST_ESP_OK(nvs_open("test_k3", NVS_READWRITE, &handle_3));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
TEST_ASSERT_TRUE(stat2.free_entries + 1 == stat1.free_entries);
TEST_ASSERT_TRUE(stat2.namespace_count == 3);
TEST_ASSERT_TRUE(stat2.total_entries == stat1.total_entries);
TEST_ASSERT_TRUE(stat2.used_entries == 8);
// create pair blobs
uint32_t blob[12];
TEST_ESP_OK(nvs_set_blob(handle_3, "bl1", &blob, sizeof(blob)));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
TEST_ASSERT_TRUE(stat1.free_entries + 3 == stat2.free_entries);
TEST_ASSERT_TRUE(stat1.namespace_count == 3);
TEST_ASSERT_TRUE(stat1.total_entries == stat2.total_entries);
TEST_ASSERT_TRUE(stat1.used_entries == 11);
// amount valid pair in namespace 2
size_t h3_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &h3_count_entries));
TEST_ASSERT_TRUE(h3_count_entries == 3);
TEST_ASSERT_TRUE(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count));
nvs_close(handle_3);
TEST_ESP_OK(nvs_flash_erase());
TEST_ESP_OK(nvs_flash_deinit());
}

View file

@ -132,14 +132,14 @@ TEST_CASE("when writing and erasing, used/erased counts are updated correctly",
CHECK(page.getErasedEntryCount() == 1);
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
char name[16];
snprintf(name, sizeof(name), "i%ld", i);
snprintf(name, sizeof(name), "i%ld", (long int)i);
CHECK(page.writeItem(1, name, i) == ESP_OK);
}
CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
CHECK(page.getErasedEntryCount() == 1);
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
char name[16];
snprintf(name, sizeof(name), "i%ld", i);
snprintf(name, sizeof(name), "i%ld", (long int)i);
CHECK(page.eraseItem(1, itemTypeOf<size_t>(), name) == ESP_OK);
}
CHECK(page.getUsedEntryCount() == 1);
@ -153,7 +153,7 @@ TEST_CASE("when page is full, adding an element fails", "[nvs]")
CHECK(page.load(0) == ESP_OK);
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
char name[16];
snprintf(name, sizeof(name), "i%ld", i);
snprintf(name, sizeof(name), "i%ld", (long int)i);
CHECK(page.writeItem(1, name, i) == ESP_OK);
}
CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL);
@ -1123,7 +1123,7 @@ TEST_CASE("crc errors in item header are handled", "[nvs]")
// add more items to make the page full
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
char item_name[Item::MAX_KEY_LENGTH + 1];
snprintf(item_name, sizeof(item_name), "item_%ld", i);
snprintf(item_name, sizeof(item_name), "item_%ld", (long int)i);
TEST_ESP_OK(storage.writeItem(1, item_name, static_cast<uint32_t>(i)));
}
@ -1252,3 +1252,137 @@ TEST_CASE("dump all performance data", "[nvs]")
std::cout << s_perf.str() << std::endl;
std::cout << "====================" << std::endl;
}
TEST_CASE("calculate used and free space", "[nvs]")
{
SpiFlashEmulator emu(6);
TEST_ESP_ERR(nvs_get_stats(NULL, NULL), ESP_ERR_INVALID_ARG);
nvs_stats_t stat1;
nvs_stats_t stat2;
TEST_ESP_ERR(nvs_get_stats(NULL, &stat1), ESP_ERR_NVS_NOT_INITIALIZED);
CHECK(stat1.free_entries == 0);
CHECK(stat1.namespace_count == 0);
CHECK(stat1.total_entries == 0);
CHECK(stat1.used_entries == 0);
nvs_handle handle = 0;
size_t h_count_entries;
TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
CHECK(h_count_entries == 0);
// init nvs
TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 6));
TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
CHECK(h_count_entries == 0);
Page p;
// after erase. empty partition
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
CHECK(stat1.free_entries != 0);
CHECK(stat1.namespace_count == 0);
CHECK(stat1.total_entries == 6 * p.ENTRY_COUNT);
CHECK(stat1.used_entries == 0);
// create namespace test_k1
nvs_handle handle_1;
TEST_ESP_OK(nvs_open("test_k1", NVS_READWRITE, &handle_1));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
CHECK(stat2.free_entries + 1 == stat1.free_entries);
CHECK(stat2.namespace_count == 1);
CHECK(stat2.total_entries == stat1.total_entries);
CHECK(stat2.used_entries == 1);
// create pair key-value com
TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x12345678));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
CHECK(stat1.free_entries + 1 == stat2.free_entries);
CHECK(stat1.namespace_count == 1);
CHECK(stat1.total_entries == stat2.total_entries);
CHECK(stat1.used_entries == 2);
// change value in com
TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x01234567));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
CHECK(stat2.free_entries == stat1.free_entries);
CHECK(stat2.namespace_count == 1);
CHECK(stat2.total_entries != 0);
CHECK(stat2.used_entries == 2);
// create pair key-value ru
TEST_ESP_OK(nvs_set_i32(handle_1, "ru", 0x00FF00FF));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
CHECK(stat1.free_entries + 1 == stat2.free_entries);
CHECK(stat1.namespace_count == 1);
CHECK(stat1.total_entries != 0);
CHECK(stat1.used_entries == 3);
// amount valid pair in namespace 1
size_t h1_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_1, &h1_count_entries));
CHECK(h1_count_entries == 2);
nvs_handle handle_2;
// create namespace test_k2
TEST_ESP_OK(nvs_open("test_k2", NVS_READWRITE, &handle_2));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
CHECK(stat2.free_entries + 1 == stat1.free_entries);
CHECK(stat2.namespace_count == 2);
CHECK(stat2.total_entries == stat1.total_entries);
CHECK(stat2.used_entries == 4);
// create pair key-value
TEST_ESP_OK(nvs_set_i32(handle_2, "su1", 0x00000001));
TEST_ESP_OK(nvs_set_i32(handle_2, "su2", 0x00000002));
TEST_ESP_OK(nvs_set_i32(handle_2, "sus", 0x00000003));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
CHECK(stat1.free_entries + 3 == stat2.free_entries);
CHECK(stat1.namespace_count == 2);
CHECK(stat1.total_entries == stat2.total_entries);
CHECK(stat1.used_entries == 7);
CHECK(stat1.total_entries == (stat1.used_entries + stat1.free_entries));
// amount valid pair in namespace 2
size_t h2_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_2, &h2_count_entries));
CHECK(h2_count_entries == 3);
CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + stat1.namespace_count));
nvs_close(handle_1);
nvs_close(handle_2);
size_t temp = h2_count_entries;
TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, &h2_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
CHECK(h2_count_entries == 0);
h2_count_entries = temp;
TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, NULL), ESP_ERR_INVALID_ARG);
nvs_handle handle_3;
// create namespace test_k3
TEST_ESP_OK(nvs_open("test_k3", NVS_READWRITE, &handle_3));
TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
CHECK(stat2.free_entries + 1 == stat1.free_entries);
CHECK(stat2.namespace_count == 3);
CHECK(stat2.total_entries == stat1.total_entries);
CHECK(stat2.used_entries == 8);
// create pair blobs
uint32_t blob[12];
TEST_ESP_OK(nvs_set_blob(handle_3, "bl1", &blob, sizeof(blob)));
TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
CHECK(stat1.free_entries + 3 == stat2.free_entries);
CHECK(stat1.namespace_count == 3);
CHECK(stat1.total_entries == stat2.total_entries);
CHECK(stat1.used_entries == 11);
// amount valid pair in namespace 2
size_t h3_count_entries;
TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &h3_count_entries));
CHECK(h3_count_entries == 3);
CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count));
nvs_close(handle_3);
}