components/nvs: add erase function

This change exposes functions to erase single key and to erase all keys from namespace.
TW6769, TW6839
This commit is contained in:
Ivan Grokhotkov 2016-09-23 00:36:53 +08:00
parent e87d80d478
commit 2a68f60874
7 changed files with 125 additions and 30 deletions

View file

@ -180,6 +180,41 @@ esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value);
esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length); esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length);
esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length); esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length);
/**
* @brief Erase key-value pair with given key name.
*
* Note that actual storage may not be updated until nvs_commit function is called.
*
* @param[in] handle Storage handle obtained with nvs_open. If handle has to be
* opened as not read only for this call to succeed.
*
* @param[in] key Key name. Maximal length is determined by the underlying
* implementation, but is guaranteed to be at least
* 16 characters. Shouldn't be empty.
*
* @return - ESP_OK if erase operation was successful
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if handle was opened as read only
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_erase_key(nvs_handle handle, const char* key);
/**
* @brief Erase all key-value pairs in a namespace
*
* Note that actual storage may not be updated until nvs_commit function is called.
*
* @param[in] handle Storage handle obtained with nvs_open. If handle has to be
* opened as not read only for this call to succeed.
*
* @return - ESP_OK if erase operation was successful
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if handle was opened as read only
* - other error codes from the underlying storage driver
*/
esp_err_t nvs_erase_all(nvs_handle handle);
/** /**
* @brief Write any pending changes to non-volatile storage * @brief Write any pending changes to non-volatile storage
* *

View file

@ -103,6 +103,36 @@ extern "C" void nvs_close(nvs_handle handle)
s_nvs_handles.erase(it); s_nvs_handles.erase(it);
} }
extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key)
{
Lock lock;
NVS_DEBUGV("%s %s\r\n", __func__, key);
HandleEntry entry;
auto err = nvs_find_ns_handle(handle, entry);
if (err != ESP_OK) {
return err;
}
if (entry.mReadOnly) {
return ESP_ERR_NVS_READ_ONLY;
}
return s_nvs_storage.eraseItem(entry.mNsIndex, key);
}
extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
{
Lock lock;
NVS_DEBUGV("%s\r\n", __func__);
HandleEntry entry;
auto err = nvs_find_ns_handle(handle, entry);
if (err != ESP_OK) {
return err;
}
if (entry.mReadOnly) {
return ESP_ERR_NVS_READ_ONLY;
}
return s_nvs_storage.eraseNamespace(entry.mNsIndex);
}
template<typename T> template<typename T>
static esp_err_t nvs_set(nvs_handle handle, const char* key, T value) static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
{ {

View file

@ -278,19 +278,6 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key)
return findItem(nsIndex, datatype, key, index, item); return findItem(nsIndex, datatype, key, index, item);
} }
esp_err_t Page::eraseEntry(size_t index)
{
auto state = mEntryTable.get(index);
assert(state == EntryState::WRITTEN || state == EntryState::EMPTY);
auto rc = alterEntryState(index, EntryState::ERASED);
if (rc != ESP_OK) {
return rc;
}
return ESP_OK;
}
esp_err_t Page::eraseEntryAndSpan(size_t index) esp_err_t Page::eraseEntryAndSpan(size_t index)
{ {
auto state = mEntryTable.get(index); auto state = mEntryTable.get(index);

View file

@ -206,8 +206,6 @@ protected:
esp_err_t writeEntryData(const uint8_t* data, size_t size); esp_err_t writeEntryData(const uint8_t* data, size_t size);
esp_err_t eraseEntry(size_t index);
esp_err_t eraseEntryAndSpan(size_t index); esp_err_t eraseEntryAndSpan(size_t index);
void updateFirstUsedEntry(size_t index, size_t span); void updateFirstUsedEntry(size_t index, size_t span);

View file

@ -69,6 +69,19 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount)
return ESP_OK; return ESP_OK;
} }
esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item)
{
size_t itemIndex = 0;
for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) {
auto err = it->findItem(nsIndex, datatype, key, itemIndex, item);
if (err == ESP_OK) {
page = it;
return ESP_OK;
}
}
return ESP_ERR_NVS_NOT_FOUND;
}
esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize)
{ {
if (mState != StorageState::ACTIVE) { if (mState != StorageState::ACTIVE) {
@ -202,6 +215,27 @@ esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key
return findPage->eraseItem(nsIndex, datatype, key); return findPage->eraseItem(nsIndex, datatype, key);
} }
esp_err_t Storage::eraseNamespace(uint8_t nsIndex)
{
if (mState != StorageState::ACTIVE) {
return ESP_ERR_NVS_NOT_INITIALIZED;
}
for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) {
while (true) {
auto err = it->eraseItem(nsIndex, ItemType::ANY, nullptr);
if (err == ESP_ERR_NVS_NOT_FOUND) {
break;
}
else if (err != ESP_OK) {
return err;
}
}
}
return ESP_OK;
}
esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize) esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize)
{ {
if (mState != StorageState::ACTIVE) { if (mState != StorageState::ACTIVE) {

View file

@ -69,13 +69,15 @@ public:
return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
} }
template<typename T>
esp_err_t eraseItem(uint8_t nsIndex, const char* key) esp_err_t eraseItem(uint8_t nsIndex, const char* key)
{ {
return eraseItem(nsIndex, itemTypeOf<T>(), key); return eraseItem(nsIndex, ItemType::ANY, key);
} }
esp_err_t eraseNamespace(uint8_t nsIndex);
void debugDump(); void debugDump();
void debugCheck(); void debugCheck();
@ -88,19 +90,7 @@ protected:
void clearNamespaces(); void clearNamespaces();
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item);
{
size_t itemIndex = 0;
for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) {
auto err = it->findItem(nsIndex, datatype, key, itemIndex, item);
if (err == ESP_OK) {
page = it;
return ESP_OK;
}
}
return ESP_ERR_NVS_NOT_FOUND;
}
protected: protected:
size_t mPageCount; size_t mPageCount;

View file

@ -386,6 +386,27 @@ TEST_CASE("can modify an item on a page which will be erased", "[nvs]")
} }
TEST_CASE("can erase items", "[nvs]")
{
SpiFlashEmulator emu(3);
Storage storage;
CHECK(storage.init(0, 3) == ESP_OK);
for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) {
char name[Item::MAX_KEY_LENGTH + 1];
snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
REQUIRE(storage.writeItem(3, name, static_cast<int>(i)) == ESP_OK);
}
CHECK(storage.writeItem(1, "foo", 32) == ESP_OK);
CHECK(storage.writeItem(2, "foo", 64) == ESP_OK);
CHECK(storage.eraseItem(2, "foo") == ESP_OK);
int val;
CHECK(storage.readItem(1, "foo", val) == ESP_OK);
CHECK(val == 32);
CHECK(storage.eraseNamespace(3) == ESP_OK);
CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND);
CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND);
}
#define TEST_ESP_ERR(rc, res) CHECK((rc) == (res)) #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res))
#define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK) #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)