KVStore
Tip: This API replaces the deprecated NVStore API.
KVStore class hierarchy
The KVStore API is a common get/set API implemented by several classes. It allows flexibility in the configuration of a storage solution that you can build by allocating several combinations of objects. For example, SecureStore can hold a TDBStore or a FileSystemStore, both implementing the KVStore API, without any change in functionality.
Developers should use the static global KVStore API when possible, to use the flexibility of KVStore configuration.
It is also possible to instantiate single objects of the classes detailed below and use the KVStore class API directly. The KVStore API presents additional functionality not present in the global API, such as incremental set (set_start
, set_add_data
and set_finalize
) and incremental get (parameter offset in function get
). You must use these APIs with caution because two calls to set_start
result in the second call to set_start
being held pending on a mutex until set_finalize
is called.
Classes implementing KVStore API:
-
Tiny Database Storage (TDBStore): A lightweight module that stores data on a block device. It is part of the KVStore class family, so it supports the get/set interface. It is designed to optimize performance (speed of access), reduce wearing of the storage and minimize storage overhead. It is also resilient to power failures.
- Requirements and assumptions: TDBStore assumes that the underlying block device is fully dedicated for it (starting offset 0). If you want to dedicate only a part of the device to TDBStore, then use a sliced block device, typically with
SlicingBlockDevice
.
- Requirements and assumptions: TDBStore assumes that the underlying block device is fully dedicated for it (starting offset 0). If you want to dedicate only a part of the device to TDBStore, then use a sliced block device, typically with
-
FileSystemStore: A lightweight implementation of the KVStore interface over file systems.
- Requirements and assumptions: FileSystemStore assumes the underlying file system qualities for resilience and file validation. If the underlying file system has no protection against power failures, then neither does FileSystemStore. When initializing this class, it is assumed that the underlying FileSystem is initialized and mounted.
-
SecureStore: A KVStore-based storage solution that provides security features on the stored data, such as encryption, authentication, rollback protection and write once, over an underlying KVStore class. It references an additional KVStore class for storing the rollback protection keys.
- Requirements and assumptions: SecureStore assumes that the underlying KVStore instances are instantiated and initialized.
KVStore class reference
Data Structures | |
struct | info |
Holds key information. More... |
Public Types | |
typedef struct mbed::KVStore::info | info_t |
Holds key information. More... |
Public Member Functions | |
virtual int | init ()=0 |
Initialize KVStore. More... | |
virtual int | deinit ()=0 |
Deinitialize KVStore. More... | |
virtual int | reset ()=0 |
Reset KVStore contents (clear all keys) More... | |
virtual int | set (const char *key, const void *buffer, size_t size, uint32_t create_flags)=0 |
Set one KVStore item, given key and value. More... | |
virtual int | get (const char *key, void *buffer, size_t buffer_size, size_t *actual_size=NULL, size_t offset=0)=0 |
Get one KVStore item, given key. More... | |
virtual int | get_info (const char *key, info_t *info=NULL)=0 |
Get information of a given key. More... | |
virtual int | remove (const char *key)=0 |
Remove a KVStore item, given key. More... | |
virtual int | set_start (set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags)=0 |
Start an incremental KVStore set sequence. More... | |
virtual int | set_add_data (set_handle_t handle, const void *value_data, size_t data_size)=0 |
Add data to incremental KVStore set sequence. More... | |
virtual int | set_finalize (set_handle_t handle)=0 |
Finalize an incremental KVStore set sequence. More... | |
virtual int | iterator_open (iterator_t *it, const char *prefix=NULL)=0 |
Start an iteration over KVStore keys. More... | |
virtual int | iterator_next (iterator_t it, char *key, size_t key_size)=0 |
Get next key in iteration. More... | |
virtual int | iterator_close (iterator_t it)=0 |
Close iteration. More... | |
bool | is_valid_key (const char *key) const |
Convenience function for checking key validity. More... |
KVStore example
/* Copyright (c) 2018 Arm Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#include "mbed.h"
#include <stdio.h>
#include <string.h>
#include "KVStore.h"
#include "kvstore_global_api.h"
#include "DeviceKey.h"
using namespace mbed;
#define EXAMPLE_KV_VALUE_LENGTH 64
#define EXAMPLE_KV_KEY_LENGTH 32
#define err_code(res) MBED_GET_ERROR_CODE(res)
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
void kv_store_global_api_example();
int main()
{
/* KV Store Static API Example */
kv_store_global_api_example();
}
void kv_store_global_api_example()
{
char kv_value_in[EXAMPLE_KV_VALUE_LENGTH] = {"kvstore_dummy_value_hello_world"};
char kv_key_in[EXAMPLE_KV_KEY_LENGTH] = {"/kv/dummy_key1"};
char kv_key_out[EXAMPLE_KV_KEY_LENGTH] = {0};
size_t actual_size = 0;
/* key information container */
kv_info_t info;
/* kv store iterator */
kv_iterator_t kvstore_it;
int i_ind = 0;
printf("--- Mbed OS KVStore static API example ---\n");
int res = MBED_ERROR_NOT_READY;
/* Start By Resetting the KV Storage */
printf("kv_reset\n");
res = kv_reset("/kv/");
printf("kv_reset -> %d\n", err_code(res));
if (strcmp(STR(MBED_CONF_STORAGE_STORAGE_TYPE), "TDB_EXTERNAL") == 0) {
res = DeviceKey::get_instance().generate_root_of_trust();
printf("DeviceKey::get_instance().generate_root_of_trust() -> %d\n", res);
}
/* Set First 'Dummy' Key/Value pair with unprotected clear value data */
printf("kv_set first dummy key\n");
res = kv_set(kv_key_in, kv_value_in, strlen(kv_value_in), 0);
printf("kv_set -> %d\n", err_code(res));
/* Read the KV Pair you've just set */
/* Start by getting key's information */
printf("kv_get_info of first key\n");
res = kv_get_info(kv_key_in, &info);
printf("kv_get_info -> %d\n", err_code(res));
printf("kv_get_info key: %s\n", kv_key_in);
printf("kv_get_info info - size: %u, flags: %lu\n", info.size, info.flags);
/* Now that you know the data value size of this key,
* allocate a buffer with matching size and get the value data */
printf("kv_get first key\n");
char *kv_first_value_out = new char[info.size + 1];
memset(kv_first_value_out, 0, info.size + 1);
res = kv_get(kv_key_in, kv_first_value_out, info.size, &actual_size);
printf("kv_get -> %d\n", err_code(res));
printf("kv_get key: %s\n", kv_key_in);
printf("kv_get value: %s\n", kv_first_value_out);
delete[] kv_first_value_out;
/* Lets set some more 'Dummy' and 'Real' KV pairs */
/* Set 'Dummy' Key2 */
printf("kv_set second dummy key \n");
res = kv_set("/kv/dummy_key2", "dummy_value2", strlen("dummy_value2"), 0);
printf("kv_set -> %d\n", err_code(res));
/* Set an authenticated-encrypted 'Dummy' key with Replay protection */
printf("kv_set third key with Confidentiality and Replay Protection flags\n");
res = kv_set("/kv/dummy_auth_enc_key", "auth_enc_value", strlen("auth_enc_value"),
KV_REQUIRE_CONFIDENTIALITY_FLAG | KV_REQUIRE_REPLAY_PROTECTION_FLAG);
printf("kv_set -> %d\n", err_code(res));
/* Set 2 non-dummy 'Real' KV pairs */
/* Set 'Real' Key 1 */
printf("kv_set Set 'Real' Key 1\n");
res = kv_set("/kv/real_key1", "real_value1", strlen("real_value1"), 0);
printf("kv_set -> %d\n", err_code(res));
/* Set 'Real' Write-Once Key2 for a key that you do not want to be removed */
printf("kv_set Set 'Real' Key 2 with flag write-once\n");
res = kv_set("/kv/real_wo_key", "real_wo_value", strlen("real_wo_value"), KV_WRITE_ONCE_FLAG);
printf("kv_set -> %d\n", err_code(res));
/* Now lets remove all of the 'Dummy' Keys and remain with the 'Real' ones */
printf("Removing 'Dummy' Keys\n");
/* Iterate and remove Keys that start with prefix 'dummy' */
res = kv_iterator_open(&kvstore_it, "dummy");
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
while (kv_iterator_next(kvstore_it, kv_key_out, EXAMPLE_KV_KEY_LENGTH) != MBED_ERROR_ITEM_NOT_FOUND) {
i_ind++;
printf("%d) Removing %s\n", i_ind, kv_key_out);
kv_remove(kv_key_out);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
}
res = kv_iterator_close(kvstore_it);
printf("Remaining with 'Real' Keys:\n");
/* Iterate on all remaining Keys */
res = kv_iterator_open(&kvstore_it, NULL);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
i_ind = 0;
while (kv_iterator_next(kvstore_it, kv_key_out, EXAMPLE_KV_KEY_LENGTH) != MBED_ERROR_ITEM_NOT_FOUND) {
i_ind++;
printf("%d) %s\n", i_ind, kv_key_out);
memset(kv_key_out, 0, EXAMPLE_KV_KEY_LENGTH);
}
res = kv_iterator_close(kvstore_it);
/* Try to remove write-once Key - should fail */
printf("kv_remove write-once file - should fail!\n");
res = kv_remove("/kv/real_wo_key");
printf("kv_remove -> %d\n", err_code(res));
/* Finally, reset will format kvstore and remove All Keys (including write-once keys) */
printf("kv_reset format kvstore (including write-once)\n");
res = kv_reset("/kv/");
printf("kv_reset -> %d\n", err_code(res));
return;
}