Mbed OS Reference
Loading...
Searching...
No Matches
TDBStore.h
1/*
2 * Copyright (c) 2018 ARM Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 * Licensed under the Apache License, Version 2.0 (the License); you may
5 * not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef MBED_TDBSTORE_H
18#define MBED_TDBSTORE_H
19
20#include <stdint.h>
21#include <stdio.h>
22#include "kvstore/KVStore.h"
23#include "blockdevice/BlockDevice.h"
24#include "blockdevice/BufferedBlockDevice.h"
25#include "rtos/Mutex.h"
26#include "mbed_error.h"
27
28namespace mbed {
29
30/**
31* \addtogroup kvstore
32* @{
33*/
34
35/**
36 * Tiny Database Storage (TDBStore) is a lightweight module that stores data on flash storage. It is part of of
37 * the KVStore class family, meaning it supports the get/set interface. It is designed to optimize performance
38 * (speed of access), reduce wearing of the flash and minimize storage overhead. It is also resilient to power
39 * failures.
40 *
41 * TDBStore assumes the underlying block device is fully dedicated to it (starting offset 0). If you want to
42 * dedicate only a part of the device to TDBStore, use a sliced block device, typically with SlicingBlockDevice.
43 */
44
45class TDBStore : public KVStore {
46public:
47
48 static const uint32_t RESERVED_AREA_SIZE = 64;
49
50 /**
51 * @brief Class constructor
52 *
53 * @param[in] bd Underlying block device.
54 */
56
57 /**
58 * @brief Class destructor
59 */
60 virtual ~TDBStore();
61
62 /**
63 * @brief Initialize TDBStore. If data exists, TDBStore will check the data integrity
64 * on initialize. If the integrity checks fails, the TDBStore will use GC to collect
65 * the available data and clean corrupted and erroneous records.
66 *
67 * @returns MBED_SUCCESS Success.
68 * @returns Negative error code on failure.
69 */
70 virtual int init();
71
72 /**
73 * @brief Deinitialize TDBStore, release and free resources.
74 *
75 * @returns MBED_SUCCESS Success.
76 */
77 virtual int deinit();
78
79
80 /**
81 * @brief Reset TDBStore contents (clear all keys) and reserved data
82 *
83 * @returns MBED_SUCCESS Success.
84 * MBED_ERROR_NOT_READY Not initialized.
85 * MBED_ERROR_READ_FAILED Unable to read from media.
86 * MBED_ERROR_WRITE_FAILED Unable to write to media.
87 */
88 virtual int reset();
89
90 /**
91 * @brief Set one TDBStore item, given key and value.
92 *
93 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
94 * @param[in] buffer Value data buffer.
95 * @param[in] size Value data size.
96 * @param[in] create_flags Flag mask.
97 *
98 * @returns MBED_SUCCESS Success.
99 * MBED_ERROR_NOT_READY Not initialized.
100 * MBED_ERROR_READ_FAILED Unable to read from media.
101 * MBED_ERROR_WRITE_FAILED Unable to write to media.
102 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
103 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
104 * MBED_ERROR_MEDIA_FULL Not enough room on media.
105 * MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
106 */
107 virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags);
108
109 /**
110 * @brief Get one TDBStore item by given key.
111 *
112 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
113 * @param[in] buffer Value data buffer.
114 * @param[in] buffer_size Value data buffer size.
115 * @param[out] actual_size Actual read size.
116 * @param[in] offset Offset to read from in data.
117 *
118 * @returns MBED_SUCCESS Success.
119 * MBED_ERROR_NOT_READY Not initialized.
120 * MBED_ERROR_READ_FAILED Unable to read from media.
121 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
122 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
123 * MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
124 * MBED_ERROR_ITEM_NOT_FOUND No such key.
125 */
126 virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size = NULL,
127 size_t offset = 0);
128
129 /**
130 * @brief Get information of a given key. The returned info contains size and flags
131 *
132 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
133 * @param[out] info Returned information structure.
134 *
135 * @returns MBED_SUCCESS Success.
136 * MBED_ERROR_NOT_READY Not initialized.
137 * MBED_ERROR_READ_FAILED Unable to read from media.
138 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
139 * MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
140 * MBED_ERROR_ITEM_NOT_FOUND No such key.
141 */
142 virtual int get_info(const char *key, info_t *info);
143
144 /**
145 * @brief Remove a TDBStore item by given key.
146 *
147 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
148 *
149 * @returns MBED_SUCCESS Success.
150 * MBED_ERROR_NOT_READY Not initialized.
151 * MBED_ERROR_READ_FAILED Unable to read from media.
152 * MBED_ERROR_WRITE_FAILED Unable to write to media.
153 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
154 * MBED_ERROR_MEDIA_FULL Not enough room on media.
155 * MBED_ERROR_ITEM_NOT_FOUND No such key.
156 * MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
157 */
158 virtual int remove(const char *key);
159
160
161 /**
162 * @brief Start an incremental TDBStore set sequence. This operation is blocking other operations.
163 * Any get/set/remove/iterator operation will be blocked until set_finalize is called.
164 *
165 * @param[out] handle Returned incremental set handle.
166 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
167 * @param[in] final_data_size Final value data size.
168 * @param[in] create_flags Flag mask.
169 *
170 * @returns MBED_SUCCESS Success.
171 * MBED_ERROR_NOT_READY Not initialized.
172 * MBED_ERROR_READ_FAILED Unable to read from media.
173 * MBED_ERROR_WRITE_FAILED Unable to write to media.
174 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
175 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
176 * MBED_ERROR_MEDIA_FULL Not enough room on media.
177 * MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
178 */
179 virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags);
180
181 /**
182 * @brief Add data to incremental TDBStore set sequence. This operation is blocking other operations.
183 * Any get/set/remove operation will be blocked until set_finalize will be called.
184 *
185 * @param[in] handle Incremental set handle.
186 * @param[in] value_data Value data to add.
187 * @param[in] data_size Value data size.
188 *
189 * @returns MBED_SUCCESS Success.
190 * MBED_ERROR_NOT_READY Not initialized.
191 * MBED_ERROR_WRITE_FAILED Unable to write to media.
192 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
193 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
194 */
195 virtual int set_add_data(set_handle_t handle, const void *value_data, size_t data_size);
196
197 /**
198 * @brief Finalize an incremental KVStore set sequence.
199 *
200 * @param[in] handle Incremental set handle.
201 *
202 * @returns MBED_SUCCESS Success.
203 * MBED_ERROR_NOT_READY Not initialized.
204 * MBED_ERROR_WRITE_FAILED Unable to write to media.
205 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
206 */
207 virtual int set_finalize(set_handle_t handle);
208
209 /**
210 * @brief Start an iteration over KVStore keys.
211 * There are no issues with any other operations while iterator is open.
212 *
213 * @param[out] it Returned iterator handle.
214 * @param[in] prefix Key prefix (null for all keys).
215 *
216 * @returns MBED_SUCCESS Success.
217 * MBED_ERROR_NOT_READY Not initialized.
218 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
219 */
220 virtual int iterator_open(iterator_t *it, const char *prefix = NULL);
221
222 /**
223 * @brief Get next key in iteration.
224 * There are no issues with any other operations while iterator is open.
225 *
226 * @param[in] it Iterator handle.
227 * @param[in] key Buffer for returned key.
228 * @param[in] key_size Key buffer size.
229 *
230 * @returns MBED_SUCCESS Success.
231 * MBED_ERROR_NOT_READY Not initialized.
232 * MBED_ERROR_READ_FAILED Unable to read from block device.
233 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
234 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
235 * MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
236 * MBED_ERROR_ITEM_NOT_FOUND No more keys found.
237 */
238 virtual int iterator_next(iterator_t it, char *key, size_t key_size);
239
240 /**
241 * @brief Close iteration.
242 *
243 * @param[in] it Iterator handle.
244 *
245 * @returns MBED_SUCCESS Success.
246 * MBED_ERROR_NOT_READY Not initialized.
247 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
248 */
249 virtual int iterator_close(iterator_t it);
250
251 /**
252 * @brief Set data in reserved area, which is a special location for special data, such as ROT.
253 * The data written to reserved area can't be overwritten.
254 *
255 * @param[in] reserved_data Reserved data buffer.
256 * @param[in] reserved_data_buf_size
257 * Reserved data buffer size.
258 *
259 * @returns MBED_SUCCESS Success.
260 * MBED_ERROR_NOT_READY Not initialized.
261 * MBED_ERROR_READ_FAILED Unable to read from media.
262 * MBED_ERROR_WRITE_FAILED Unable to write to media.
263 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
264 * MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
265 */
266 virtual int reserved_data_set(const void *reserved_data, size_t reserved_data_buf_size);
267
268 /**
269 * @brief Get data from reserved area, which is a special location for special data, such as ROT.
270 *
271 * @param[in] reserved_data Reserved data buffer.
272 * @param[in] reserved_data_buf_size
273 * Reserved data buffer size.
274 * @param[in] actual_data_size Return data size.
275 *
276 * @returns MBED_SUCCESS Success.
277 * MBED_ERROR_NOT_READY Not initialized.
278 * MBED_ERROR_READ_FAILED Unable to read from media.
279 * MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
280 * MBED_ERROR_INVALID_DATA_DETECTED Data is corrupt.
281 * MBED_ERROR_ITEM_NOT_FOUND No reserved data was written.
282 */
283 virtual int reserved_data_get(void *reserved_data, size_t reserved_data_buf_size,
284 size_t *actual_data_size = 0);
285
286#if !defined(DOXYGEN_ONLY)
287private:
288
289 typedef struct {
290 uint32_t address;
291 size_t size;
292 } tdbstore_area_data_t;
293
294 static const int _num_areas = 2;
295 static const int _max_open_iterators = 16;
296
297 rtos::Mutex _mutex;
298 rtos::Mutex _inc_set_mutex;
299 void *_ram_table;
300 size_t _max_keys;
301 size_t _num_keys;
302 BlockDevice *_bd;
303 BufferedBlockDevice *_buff_bd;
304 uint32_t _free_space_offset;
305 uint32_t _master_record_offset;
306 uint32_t _master_record_size;
307 bool _is_initialized;
308 int _active_area;
309 uint16_t _active_area_version;
310 size_t _size;
311 tdbstore_area_data_t _area_params[_num_areas];
312 uint32_t _prog_size;
313 uint8_t *_work_buf;
314 size_t _work_buf_size;
315 char *_key_buf;
316 void *_inc_set_handle;
317 void *_iterator_table[_max_open_iterators];
318
319 /**
320 * @brief Read a block from an area.
321 *
322 * @param[in] area Area.
323 * @param[in] offset Offset in area.
324 * @param[in] size Number of bytes to read.
325 * @param[in] buf Output buffer.
326 *
327 * @returns 0 for success, nonzero for failure.
328 */
329 int read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf);
330
331 /**
332 * @brief Write a block to an area.
333 *
334 * @param[in] area Area.
335 * @param[in] offset Offset in area.
336 * @param[in] size Number of bytes to write.
337 * @param[in] buf Input buffer.
338 *
339 * @returns 0 for success, non-zero for failure.
340 */
341 int write_area(uint8_t area, uint32_t offset, uint32_t size, const void *buf);
342
343 /**
344 * @brief Reset an area (erase its start).
345 * This erases master record, but preserves the
346 * reserved area data.
347 *
348 * @param[in] area Area.
349 *
350 * @returns 0 for success, nonzero for failure.
351 */
352 int reset_area(uint8_t area);
353
354 /**
355 * @brief Erase an area.
356 *
357 * @param[in] area Area.
358 * @param[in] offset Offset in area.
359 * @param[in] size Number of bytes to erase.
360 *
361 * @returns 0 for success, nonzero for failure.
362 */
363 int erase_area(uint8_t area, uint32_t offset, uint32_t size);
364
365 /**
366 * @brief Calculate addresses and sizes of areas.
367 */
368 void calc_area_params();
369
370 /**
371 * @brief Read a TDBStore record from a given location.
372 *
373 * @param[in] area Area.
374 * @param[in] offset Offset of record in area.
375 * @param[out] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
376 * @param[out] data_buf Data buffer.
377 * @param[in] data_buf_size Data buffer size.
378 * @param[out] actual_data_size Actual data size.
379 * @param[in] data_offset Offset in data.
380 * @param[in] copy_key Copy key to user buffer.
381 * @param[in] copy_data Copy data to user buffer.
382 * @param[in] check_expected_key Check whether key belongs to this record.
383 * @param[in] calc_hash Calculate hash (on key).
384 * @param[out] hash Calculated hash.
385 * @param[out] flags Record flags.
386 * @param[out] next_offset Offset of next record.
387 *
388 * @returns 0 for success, nonzero for failure.
389 */
390 int read_record(uint8_t area, uint32_t offset, char *key,
391 void *data_buf, uint32_t data_buf_size,
392 uint32_t &actual_data_size, size_t data_offset, bool copy_key,
393 bool copy_data, bool check_expected_key, bool calc_hash,
394 uint32_t &hash, uint32_t &flags, uint32_t &next_offset);
395
396 /**
397 * @brief Write a master record of a given area.
398 *
399 * @param[in] area Area.
400 * @param[in] version Area version.
401 * @param[out] next_offset Offset of next record.
402 *
403 * @returns 0 for success, nonzero for failure.
404 */
405 int write_master_record(uint8_t area, uint16_t version, uint32_t &next_offset);
406
407 /**
408 * @brief Copy a record from one area to the opposite one.
409 *
410 * @param[in] from_area Area to copy record from.
411 * @param[in] from_offset Offset in source area.
412 * @param[in] to_offset Offset in destination area.
413 * @param[out] to_next_offset Offset of next record in destination area.
414 *
415 * @returns 0 for success, nonzero for failure.
416 */
417 int copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset,
418 uint32_t &to_next_offset);
419
420 /**
421 * @brief Garbage collection (compact all records from active area to the standby one).
422 *
423 * @returns 0 for success, nonzero for failure.
424 */
425 int garbage_collection();
426
427 /**
428 * @brief Return record size given key and data size.
429 *
430 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
431 * @param[in] data_size Data size.
432 *
433 * @returns record size.
434 */
435 uint32_t record_size(const char *key, uint32_t data_size);
436
437 /**
438 * @brief Find a record given key
439 *
440 * @param[in] area Area.
441 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
442 * @param[out] offset Offset of record.
443 * @param[out] ram_table_ind Index in RAM table (target one if not found).
444 * @param[out] hash Calculated key hash.
445 *
446 * @returns 0 for success, nonzero for failure.
447 */
448 int find_record(uint8_t area, const char *key, uint32_t &offset,
449 uint32_t &ram_table_ind, uint32_t &hash);
450 /**
451 * @brief Actual logics of get API (also covers all other get APIs).
452 *
453 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
454 * @param[in] copy_data Copy data to user buffer.
455 * @param[in] data_buf Buffer to store data on.
456 * @param[in] data_buf_size Data buffer size (bytes).
457 * @param[out] actual_data_size Actual data size (bytes).
458 * @param[out] flags Flags.
459 *
460 * @returns 0 for success, nonzero for failure.
461 */
462 int do_get(const char *key, bool copy_data,
463 void *data_buf, uint32_t data_buf_size, uint32_t &actual_data_size,
464 uint32_t &flags);
465
466 /**
467 * @brief Actual logics of set API (covers also the remove API).
468 *
469 * @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
470 * @param[in] data_buf Data buffer.
471 * @param[in] data_buf_size Data buffer size (bytes).
472 * @param[in] flags Flags.
473 *
474 * @returns 0 for success, nonzero for failure.
475 */
476 int do_set(const char *key, const void *data_buf, uint32_t data_buf_size, uint32_t flags);
477
478 /**
479 * @brief Build RAM table and update _free_space_offset (scanning all the records in the area).
480 *
481 * @returns 0 for success, nonzero for failure.
482 */
483 int build_ram_table();
484
485 /**
486 * @brief Increment maximum number of keys and reallocate RAM table accordingly.
487 *
488 * @param[out] ram_table Updated RAM table.
489 *
490 * @returns 0 for success, nonzero for failure.
491 */
492 int increment_max_keys(void **ram_table = 0);
493
494 /**
495 * @brief Calculate offset from start of erase unit.
496 *
497 * @param[in] area Area.
498 * @param[in] offset Offset in area.
499 * @param[out] offset_from_start Offset from start of erase unit.
500 * @param[out] dist_to_end Distance to end of erase unit.
501 *
502 * @returns offset in erase unit.
503 */
504 void offset_in_erase_unit(uint8_t area, uint32_t offset, uint32_t &offset_from_start,
505 uint32_t &dist_to_end);
506
507 /**
508 * @brief Before writing a record, check whether you are crossing an erase unit.
509 * If you do, check if it's erased, and erase it if not.
510 *
511 * @param[in] area Area.
512 * @param[in] offset Offset in area.
513 * @param[in] size Write size.
514 * @param[in] force_check Force checking.
515 *
516 * @returns 0 for success, nonzero for failure.
517 */
518 int check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size,
519 bool force_check = false);
520
521 /**
522 * @brief Get data from reserved area - worker function.
523 * This verifies that reserved data on both areas have
524 * correct checksums. If given pointer is not NULL, also
525 * write the reserved data to buffer. If checksums are not
526 * valid, return error code, and don't write anything to any
527 * pointers.
528 *
529 * @param[out] reserved_data Reserved data buffer (NULL to return nothing).
530 * @param[in] reserved_data_buf_size
531 * Reserved data buffer size.
532 * @param[out] actual_data_size If not NULL, return actual data size.
533 * @param[out] copy_trailer If not NULL, copy the trailer content to given buffer.
534 *
535 * @returns 0 on success or a negative error code on failure
536 */
537 int do_reserved_data_get(void *reserved_data, size_t reserved_data_buf_size,
538 size_t *actual_data_size = 0, void *copy_trailer = 0);
539
540 /**
541 * @brief Update all iterators after adding or deleting of keys.
542 *
543 * @param[in] added True if added, false if deleted.
544 * @param[in] ram_table_ind RAM table index.
545 *
546 * @returns none
547 */
548 void update_all_iterators(bool added, uint32_t ram_table_ind);
549
550#endif
551
552};
553/** @}*/
554
555} // namespace mbed
556
557#endif
A hardware device capable of writing and reading blocks.
Definition: BlockDevice.h:53
Block device which allows minimal read and program sizes (of 1) for the underlying BD using a buffer ...
KVStore class.
Definition: KVStore.h:38
Tiny Database Storage (TDBStore) is a lightweight module that stores data on flash storage.
Definition: TDBStore.h:45
TDBStore(BlockDevice *bd)
Class constructor.
virtual int get_info(const char *key, info_t *info)
Get information of a given key.
virtual int iterator_open(iterator_t *it, const char *prefix=NULL)
Start an iteration over KVStore keys.
virtual int remove(const char *key)
Remove a TDBStore item by given key.
virtual int iterator_next(iterator_t it, char *key, size_t key_size)
Get next key in iteration.
virtual ~TDBStore()
Class destructor.
virtual int set_finalize(set_handle_t handle)
Finalize an incremental KVStore set sequence.
virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags)
Set one TDBStore item, given key and value.
virtual int iterator_close(iterator_t it)
Close iteration.
virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags)
Start an incremental TDBStore set sequence.
virtual int deinit()
Deinitialize TDBStore, release and free resources.
virtual int reset()
Reset TDBStore contents (clear all keys) and reserved data.
virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size=NULL, size_t offset=0)
Get one TDBStore item by given key.
virtual int reserved_data_get(void *reserved_data, size_t reserved_data_buf_size, size_t *actual_data_size=0)
Get data from reserved area, which is a special location for special data, such as ROT.
virtual int set_add_data(set_handle_t handle, const void *value_data, size_t data_size)
Add data to incremental TDBStore set sequence.
virtual int init()
Initialize TDBStore.
virtual int reserved_data_set(const void *reserved_data, size_t reserved_data_buf_size)
Set data in reserved area, which is a special location for special data, such as ROT.
The Mutex class is used to synchronize the execution of threads.
Definition: Mutex.h:70
Holds key information.
Definition: KVStore.h:56