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:
parent
bdadd95dd7
commit
c93626db3f
10 changed files with 505 additions and 4 deletions
|
@ -356,6 +356,88 @@ esp_err_t nvs_commit(nvs_handle handle);
|
||||||
*/
|
*/
|
||||||
void nvs_close(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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
@ -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);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
} // namespace nvs
|
||||||
|
|
|
@ -133,6 +133,8 @@ public:
|
||||||
|
|
||||||
void debugDump() const;
|
void debugDump() const;
|
||||||
|
|
||||||
|
esp_err_t calcEntries(nvs_stats_t &nvsStats);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
class Header
|
class Header
|
||||||
|
|
|
@ -197,4 +197,26 @@ esp_err_t PageManager::activatePage()
|
||||||
return ESP_OK;
|
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
|
} // namespace nvs
|
||||||
|
|
|
@ -50,6 +50,8 @@ public:
|
||||||
|
|
||||||
esp_err_t requestNewPage();
|
esp_err_t requestNewPage();
|
||||||
|
|
||||||
|
esp_err_t fillStats(nvs_stats_t& nvsStats);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Iterator;
|
friend class Iterator;
|
||||||
|
|
||||||
|
|
|
@ -291,4 +291,37 @@ void Storage::debugCheck()
|
||||||
}
|
}
|
||||||
#endif //ESP_PLATFORM
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,9 @@ public:
|
||||||
|
|
||||||
void debugCheck();
|
void debugCheck();
|
||||||
|
|
||||||
|
esp_err_t fillStats(nvs_stats_t& nvsStats);
|
||||||
|
|
||||||
|
esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -65,3 +65,151 @@ TEST_CASE("various nvs tests", "[nvs]")
|
||||||
|
|
||||||
nvs_close(handle_2);
|
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());
|
||||||
|
}
|
||||||
|
|
|
@ -132,14 +132,14 @@ TEST_CASE("when writing and erasing, used/erased counts are updated correctly",
|
||||||
CHECK(page.getErasedEntryCount() == 1);
|
CHECK(page.getErasedEntryCount() == 1);
|
||||||
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
|
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
|
||||||
char name[16];
|
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, name, i) == ESP_OK);
|
||||||
}
|
}
|
||||||
CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
|
CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
|
||||||
CHECK(page.getErasedEntryCount() == 1);
|
CHECK(page.getErasedEntryCount() == 1);
|
||||||
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
|
for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
|
||||||
char name[16];
|
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.eraseItem(1, itemTypeOf<size_t>(), name) == ESP_OK);
|
||||||
}
|
}
|
||||||
CHECK(page.getUsedEntryCount() == 1);
|
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);
|
CHECK(page.load(0) == ESP_OK);
|
||||||
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
|
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
|
||||||
char name[16];
|
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, name, i) == ESP_OK);
|
||||||
}
|
}
|
||||||
CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL);
|
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
|
// add more items to make the page full
|
||||||
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
|
for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
|
||||||
char item_name[Item::MAX_KEY_LENGTH + 1];
|
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)));
|
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 << s_perf.str() << std::endl;
|
||||||
std::cout << "====================" << 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue