mirror of https://github.com/ARMmbed/mbed-os.git
556 lines
23 KiB
C++
556 lines
23 KiB
C++
/*
|
|
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef MBED_TDBSTORE_H
|
|
#define MBED_TDBSTORE_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include "KVStore.h"
|
|
#include "BlockDevice.h"
|
|
#include "BufferedBlockDevice.h"
|
|
#include "PlatformMutex.h"
|
|
|
|
namespace mbed {
|
|
|
|
/** TDBStore class
|
|
*
|
|
* Lightweight Key Value storage over a block device
|
|
*/
|
|
|
|
class TDBStore : public KVStore {
|
|
public:
|
|
|
|
static const uint32_t RESERVED_AREA_SIZE = 64;
|
|
|
|
/**
|
|
* @brief Class constructor
|
|
*
|
|
* @param[in] bd Underlying block device. The BlockDevice
|
|
* can be any BlockDevice with flash characteristics.
|
|
* If using a BlockDevice without flash, such as SDBlockDevice,
|
|
* please add the FlashSimBlockDevice on top of it.
|
|
*
|
|
* @returns none
|
|
*/
|
|
TDBStore(BlockDevice *bd);
|
|
|
|
/**
|
|
* @brief Class destructor
|
|
*
|
|
* @returns none
|
|
*/
|
|
virtual ~TDBStore();
|
|
|
|
/**
|
|
* @brief Initialize TDBStore. If data exists, TDBStore will check the data integrity
|
|
* on initialize. If the integrity checks fails, the TDBStore will use GC to collect
|
|
* the available data and clean corrupted and erroneous records.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* @returns Negative error code on failure.
|
|
*/
|
|
virtual int init();
|
|
|
|
/**
|
|
* @brief Deinitialize TDBStore, release and free resources.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
*/
|
|
virtual int deinit();
|
|
|
|
|
|
/**
|
|
* @brief Reset TDBStore contents (clear all keys)
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
*/
|
|
virtual int reset();
|
|
|
|
/**
|
|
* @brief Set one TDBStore item, given key and value.
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] buffer Value data buffer.
|
|
* @param[in] size Value data size.
|
|
* @param[in] create_flags Flag mask.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
* MBED_ERROR_MEDIA_FULL Not enough room on media.
|
|
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
|
|
*/
|
|
virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags);
|
|
|
|
/**
|
|
* @brief Get one TDBStore item by given key.
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] buffer Value data buffer.
|
|
* @param[in] buffer_size Value data buffer size.
|
|
* @param[out] actual_size Actual read size.
|
|
* @param[in] offset Offset to read from in data.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
|
|
* MBED_ERROR_ITEM_NOT_FOUND No such key.
|
|
*/
|
|
virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size = NULL,
|
|
size_t offset = 0);
|
|
|
|
/**
|
|
* @brief Get information of a given key. The returned info contains size and flags
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[out] info Returned information structure.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
|
|
* MBED_ERROR_ITEM_NOT_FOUND No such key.
|
|
*/
|
|
virtual int get_info(const char *key, info_t *info);
|
|
|
|
/**
|
|
* @brief Remove a TDBStore item by given key.
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_MEDIA_FULL Not enough room on media.
|
|
* MBED_ERROR_ITEM_NOT_FOUND No such key.
|
|
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
|
|
*/
|
|
virtual int remove(const char *key);
|
|
|
|
|
|
/**
|
|
* @brief Start an incremental TDBStore set sequence. This operation is blocking other operations.
|
|
* Any get/set/remove/iterator operation will be blocked until set_finalize is called.
|
|
*
|
|
* @param[out] handle Returned incremental set handle.
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] final_data_size Final value data size.
|
|
* @param[in] create_flags Flag mask.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
* MBED_ERROR_MEDIA_FULL Not enough room on media.
|
|
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
|
|
*/
|
|
virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags);
|
|
|
|
/**
|
|
* @brief Add data to incremental TDBStore set sequence. This operation is blocking other operations.
|
|
* Any get/set/remove operation will be blocked until set_finalize will be called.
|
|
*
|
|
* @param[in] handle Incremental set handle.
|
|
* @param[in] value_data Value data to add.
|
|
* @param[in] data_size Value data size.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
*/
|
|
virtual int set_add_data(set_handle_t handle, const void *value_data, size_t data_size);
|
|
|
|
/**
|
|
* @brief Finalize an incremental KVStore set sequence.
|
|
*
|
|
* @param[in] handle Incremental set handle.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
*/
|
|
virtual int set_finalize(set_handle_t handle);
|
|
|
|
/**
|
|
* @brief Start an iteration over KVStore keys.
|
|
* There are no issues with any other operations while iterator is open.
|
|
*
|
|
* @param[out] it Returned iterator handle.
|
|
* @param[in] prefix Key prefix (null for all keys).
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
*/
|
|
virtual int iterator_open(iterator_t *it, const char *prefix = NULL);
|
|
|
|
/**
|
|
* @brief Get next key in iteration.
|
|
* There are no issues with any other operations while iterator is open.
|
|
*
|
|
* @param[in] it Iterator handle.
|
|
* @param[in] key Buffer for returned key.
|
|
* @param[in] key_size Key buffer size.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from block device.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
|
|
* MBED_ERROR_ITEM_NOT_FOUND No more keys found.
|
|
*/
|
|
virtual int iterator_next(iterator_t it, char *key, size_t key_size);
|
|
|
|
/**
|
|
* @brief Close iteration.
|
|
*
|
|
* @param[in] it Iterator handle.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
*/
|
|
virtual int iterator_close(iterator_t it);
|
|
|
|
/**
|
|
* @brief Set data in reserved area, which is a special location for special data, such as ROT.
|
|
* The data written to reserved area can't be overwritten.
|
|
*
|
|
* @param[in] reserved_data Reserved data buffer.
|
|
* @param[in] reserved_data_buf_size
|
|
* Reserved data buffer size.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_WRITE_FAILED Unable to write to media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
|
|
*/
|
|
virtual int reserved_data_set(const void *reserved_data, size_t reserved_data_buf_size);
|
|
|
|
/**
|
|
* @brief Get data from reserved area, which is a special location for special data, such as ROT.
|
|
*
|
|
* @param[in] reserved_data Reserved data buffer.
|
|
* @param[in] reserved_data_buf_size
|
|
* Reserved data buffer size.
|
|
* @param[in] actual_data_size Return data size.
|
|
*
|
|
* @returns MBED_SUCCESS Success.
|
|
* MBED_ERROR_NOT_READY Not initialized.
|
|
* MBED_ERROR_READ_FAILED Unable to read from media.
|
|
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
|
|
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
|
|
* MBED_ERROR_ITEM_NOT_FOUND No reserved data was written.
|
|
*/
|
|
virtual int reserved_data_get(void *reserved_data, size_t reserved_data_buf_size,
|
|
size_t *actual_data_size = 0);
|
|
|
|
#if !defined(DOXYGEN_ONLY)
|
|
private:
|
|
|
|
typedef struct {
|
|
uint32_t address;
|
|
size_t size;
|
|
} tdbstore_area_data_t;
|
|
|
|
static const int _num_areas = 2;
|
|
static const int _max_open_iterators = 16;
|
|
|
|
PlatformMutex _mutex;
|
|
PlatformMutex _inc_set_mutex;
|
|
void *_ram_table;
|
|
size_t _max_keys;
|
|
size_t _num_keys;
|
|
BlockDevice *_bd;
|
|
BufferedBlockDevice *_buff_bd;
|
|
uint32_t _free_space_offset;
|
|
uint32_t _master_record_offset;
|
|
uint32_t _master_record_size;
|
|
bool _is_initialized;
|
|
int _active_area;
|
|
uint16_t _active_area_version;
|
|
size_t _size;
|
|
tdbstore_area_data_t _area_params[_num_areas];
|
|
uint32_t _prog_size;
|
|
uint8_t *_work_buf;
|
|
char *_key_buf;
|
|
bool _variant_bd_erase_unit_size;
|
|
void *_inc_set_handle;
|
|
void *_iterator_table[_max_open_iterators];
|
|
|
|
/**
|
|
* @brief Read a block from an area.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
* @param[in] size Number of bytes to read.
|
|
* @param[in] buf Output buffer.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf);
|
|
|
|
/**
|
|
* @brief Write a block to an area.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
* @param[in] size Number of bytes to write.
|
|
* @param[in] buf Input buffer.
|
|
*
|
|
* @returns 0 for success, non-zero for failure.
|
|
*/
|
|
int write_area(uint8_t area, uint32_t offset, uint32_t size, const void *buf);
|
|
|
|
/**
|
|
* @brief Reset an area (erase its start).
|
|
*
|
|
* @param[in] area Area.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int reset_area(uint8_t area);
|
|
|
|
/**
|
|
* @brief Erase an erase unit.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int erase_erase_unit(uint8_t area, uint32_t offset);
|
|
|
|
/**
|
|
* @brief Calculate addresses and sizes of areas.
|
|
*/
|
|
void calc_area_params();
|
|
|
|
/**
|
|
* @brief Read a TDBStore record from a given location.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset of record in area.
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] data_buf Data buffer.
|
|
* @param[in] data_buf_size Data buffer size.
|
|
* @param[out] actual_data_size Actual data size.
|
|
* @param[in] data_offset Offset in data.
|
|
* @param[in] copy_key Copy key to user buffer.
|
|
* @param[in] copy_data Copy data to user buffer.
|
|
* @param[in] check_expected_key Check whether key belongs to this record.
|
|
* @param[in] calc_hash Calculate hash (on key).
|
|
* @param[out] hash Calculated hash.
|
|
* @param[out] flags Record flags.
|
|
* @param[out] next_offset Offset of next record.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int read_record(uint8_t area, uint32_t offset, char *key,
|
|
void *data_buf, uint32_t data_buf_size,
|
|
uint32_t &actual_data_size, size_t data_offset, bool copy_key,
|
|
bool copy_data, bool check_expected_key, bool calc_hash,
|
|
uint32_t &hash, uint32_t &flags, uint32_t &next_offset);
|
|
|
|
/**
|
|
* @brief Write a master record of a given area.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] version Area version.
|
|
* @param[out] next_offset Offset of next record.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int write_master_record(uint8_t area, uint16_t version, uint32_t &next_offset);
|
|
|
|
/**
|
|
* @brief Copy a record from one area to the opposite one.
|
|
*
|
|
* @param[in] from_area Area to copy record from.
|
|
* @param[in] from_offset Offset in source area.
|
|
* @param[in] to_offset Offset in destination area.
|
|
* @param[out] to_next_offset Offset of next record in destination area.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset,
|
|
uint32_t &to_next_offset);
|
|
|
|
/**
|
|
* @brief Garbage collection (compact all records from active area to the standby one).
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int garbage_collection();
|
|
|
|
/**
|
|
* @brief Return record size given key and data size.
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] data_size Data size.
|
|
*
|
|
* @returns record size.
|
|
*/
|
|
uint32_t record_size(const char *key, uint32_t data_size);
|
|
|
|
/**
|
|
* @brief Find a record given key
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[out] offset Offset of record.
|
|
* @param[out] ram_table_ind Index in RAM table (target one if not found).
|
|
* @param[out] hash Calculated key hash.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int find_record(uint8_t area, const char *key, uint32_t &offset,
|
|
uint32_t &ram_table_ind, uint32_t &hash);
|
|
/**
|
|
* @brief Actual logics of get API (also covers all other get APIs).
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] copy_data Copy data to user buffer.
|
|
* @param[in] data_buf Buffer to store data on.
|
|
* @param[in] data_buf_size Data buffer size (bytes).
|
|
* @param[out] actual_data_size Actual data size (bytes).
|
|
* @param[out] flags Flags.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int do_get(const char *key, bool copy_data,
|
|
void *data_buf, uint32_t data_buf_size, uint32_t &actual_data_size,
|
|
uint32_t &flags);
|
|
|
|
/**
|
|
* @brief Actual logics of set API (covers also the remove API).
|
|
*
|
|
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
|
|
* @param[in] data_buf Data buffer.
|
|
* @param[in] data_buf_size Data buffer size (bytes).
|
|
* @param[in] flags Flags.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int do_set(const char *key, const void *data_buf, uint32_t data_buf_size, uint32_t flags);
|
|
|
|
/**
|
|
* @brief Build RAM table and update _free_space_offset (scanning all the records in the area).
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int build_ram_table();
|
|
|
|
/**
|
|
* @brief Increment maximum number of keys and reallocate RAM table accordingly.
|
|
*
|
|
* @param[out] ram_table Updated RAM table.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int increment_max_keys(void **ram_table = 0);
|
|
|
|
/**
|
|
* @brief Calculate offset from start of erase unit.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
* @param[out] offset_from_start Offset from start of erase unit.
|
|
* @param[out] dist_to_end Distance to end of erase unit.
|
|
*
|
|
* @returns offset in erase unit.
|
|
*/
|
|
void offset_in_erase_unit(uint8_t area, uint32_t offset, uint32_t &offset_from_start,
|
|
uint32_t &dist_to_end);
|
|
|
|
/**
|
|
* @brief Check whether erase unit is erased (from offset until end of unit).
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
* @param[out] erased Unit is erased.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int is_erase_unit_erased(uint8_t area, uint32_t offset, bool &erased);
|
|
|
|
/**
|
|
* @brief Before writing a record, check whether you are crossing an erase unit.
|
|
* If you do, check if it's erased, and erase it if not.
|
|
*
|
|
* @param[in] area Area.
|
|
* @param[in] offset Offset in area.
|
|
* @param[in] size Write size.
|
|
* @param[in] force_check Force checking.
|
|
*
|
|
* @returns 0 for success, nonzero for failure.
|
|
*/
|
|
int check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size,
|
|
bool force_check = false);
|
|
|
|
/**
|
|
* @brief Get data from reserved area - worker function.
|
|
*
|
|
* @param[in] reserved_data Reserved data buffer (0 to return nothing).
|
|
* @param[in] reserved_data_buf_size
|
|
* Reserved data buffer size.
|
|
* @param[in] actual_data_size Return data size.
|
|
*
|
|
* @returns 0 on success or a negative error code on failure
|
|
*/
|
|
int do_reserved_data_get(void *reserved_data, size_t reserved_data_buf_size,
|
|
size_t *actual_data_size = 0);
|
|
|
|
/**
|
|
* @brief Update all iterators after adding or deleting of keys.
|
|
*
|
|
* @param[in] added True if added, false if deleted.
|
|
* @param[in] ram_table_ind RAM table index.
|
|
*
|
|
* @returns none
|
|
*/
|
|
void update_all_iterators(bool added, uint32_t ram_table_ind);
|
|
|
|
#endif
|
|
|
|
};
|
|
/** @}*/
|
|
|
|
} // namespace mbed
|
|
|
|
#endif
|