1 /*
2 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3 */
4
5 #include <stdint.h>
6
7 #include "kv.h"
8
9 #include "kv_conf.h"
10 #include "kv_adapt.h"
11 #include "kv_types.h"
12
13 static kv_mgr_t g_kv_mgr;
14
15 static void kv_gc_task(void *arg);
16
17 kv_item_t *kv_item_traverse(item_func func, uint8_t blk_idx, const char *key);
18
19 /******************************************************/
20 /****************** Internal Interface ****************/
21 /******************************************************/
22
23 /**
24 * @brief CRC-8: the poly is 0x31 (x^8 + x^5 + x^4 + 1)
25 *
26 * @param[in] buf the buffer which is need calculate crc
27 * @param[in] length the length of the buffer
28 *
29 * @return the crc value
30 */
calc_crc8(uint8_t * buf,uint16_t length)31 static uint8_t calc_crc8(uint8_t *buf, uint16_t length)
32 {
33 uint8_t crc = 0x00;
34 uint8_t i = 0;
35
36 while (length--) {
37 crc ^= *buf++;
38 for (i = 8; i > 0; i--) {
39 if (crc & 0x80) {
40 crc = (crc << 1) ^ 0x31;
41 } else {
42 crc <<= 1;
43 }
44 }
45 }
46
47 return crc;
48 }
49
50 /**
51 * @brief Trigger garbage collection process
52 *
53 * @return none
54 */
kv_trigger_gc(void)55 static void kv_trigger_gc(void)
56 {
57 if (g_kv_mgr.gc_trigger != 0) {
58 return;
59 }
60
61 g_kv_mgr.gc_waiter = 0;
62 g_kv_mgr.gc_trigger = 1;
63 kv_start_task("kv_gc", kv_gc_task, NULL, KV_TASK_STACK_SIZE);
64 }
65
66 /**
67 * @brief Free item resource
68 *
69 * @param[in] item pointer to item
70 *
71 * @return none
72 */
kv_item_free(kv_item_t * item)73 static void kv_item_free(kv_item_t *item)
74 {
75 if (item) {
76 if (item->store) {
77 kv_free(item->store);
78 }
79 kv_free(item);
80 }
81 }
82
83 /**
84 * @brief Set block state bit
85 *
86 * @param[in] blk_idx the position of the block index
87 * @param[in] state the state which want to set
88 *
89 * @return 0 on success, otherwise will be failed
90 */
kv_set_block_state(uint8_t blk_idx,uint8_t state)91 static int32_t kv_set_block_state(uint8_t blk_idx, uint8_t state)
92 {
93 int32_t ret;
94
95 uint32_t pos = (blk_idx << KV_BLOCK_SIZE_BITS) + KV_STATE_OFFSET;
96
97 ret = kv_flash_write(pos, &state, 1);
98 if (ret != KV_OK) {
99 return ret;
100 }
101
102 g_kv_mgr.block_info[blk_idx].state = state;
103
104 return KV_OK;
105 }
106
107 /**
108 * @brief Set item state bit
109 *
110 * @param[in] pos the position of the item
111 * @param[in] state the state which want to set
112 *
113 * @return 0 on success, otherwise will be failed
114 */
kv_set_item_state(kv_size_t pos,uint8_t state)115 static int32_t kv_set_item_state(kv_size_t pos, uint8_t state)
116 {
117 return kv_flash_write(pos + KV_STATE_OFFSET, &state, 1);
118 }
119
120 /**
121 * @brief Format block header
122 *
123 * @param[in] blk_idx the index of the block
124 *
125 * @return 0 on success, otherwise will be failed
126 */
kv_block_format(uint8_t blk_idx)127 static int32_t kv_block_format(uint8_t blk_idx)
128 {
129 block_hdr_t hdr;
130
131 kv_size_t pos = (blk_idx << KV_BLOCK_SIZE_BITS);
132
133 memset(&hdr, 0, sizeof(block_hdr_t));
134 hdr.magic = KV_BLOCK_MAGIC_NUM;
135
136 if (!kv_flash_erase(pos, KV_BLOCK_SIZE)) {
137 hdr.state = KV_BLOCK_STATE_CLEAN;
138 } else {
139 return KV_ERR_FLASH_ERASE;
140 }
141
142 if (kv_flash_write(pos, &hdr, KV_BLOCK_HDR_SIZE) != KV_OK) {
143 return KV_ERR_FLASH_WRITE;
144 }
145
146 g_kv_mgr.block_info[blk_idx].state = KV_BLOCK_STATE_CLEAN;
147 g_kv_mgr.block_info[blk_idx].space = KV_BLOCK_SIZE - KV_BLOCK_HDR_SIZE;
148 g_kv_mgr.clean_blk_nums++;
149
150 return KV_OK;
151 }
152
153 /**
154 * @brief Calculcate the item wtite position
155 *
156 * @param[in] len the item length
157 *
158 * @return write position, 0 means there is no space to store
159 */
kv_calc_position(uint16_t len)160 static kv_size_t kv_calc_position(uint16_t len)
161 {
162 uint8_t blk_idx;
163 block_info_t *blk_info;
164
165 #if KV_BLOCK_NUMS > KV_RESERVED_BLOCKS + 1
166 uint8_t i;
167 uint32_t blk_start;
168 #endif
169
170 blk_idx = (g_kv_mgr.write_pos) >> KV_BLOCK_SIZE_BITS;
171 blk_info = &(g_kv_mgr.block_info[blk_idx]);
172
173 if (blk_info->space > len) {
174 if (((blk_info->space - len) < KV_ITEM_MAX_LEN) && \
175 (g_kv_mgr.clean_blk_nums <= KV_RESERVED_BLOCKS)) {
176 kv_trigger_gc();
177 }
178 return g_kv_mgr.write_pos;
179 }
180
181 if(g_kv_mgr.clean_blk_nums <= KV_RESERVED_BLOCKS){
182 uint8_t blk_idx_tmp;
183 block_info_t *blk_info_tmp;
184 kv_trigger_gc();
185 blk_idx_tmp = (g_kv_mgr.write_pos) >> KV_BLOCK_SIZE_BITS;
186 blk_info_tmp = &(g_kv_mgr.block_info[blk_idx_tmp]);
187
188 if(blk_info_tmp->space >= len + KV_ITEM_MAX_LEN){
189 return g_kv_mgr.write_pos;
190 }
191 }
192
193 #if KV_BLOCK_NUMS > KV_RESERVED_BLOCKS + 1
194 for (i = blk_idx + 1; i != blk_idx; i++) {
195 if (i == KV_BLOCK_NUMS) {
196 i = 0;
197 }
198
199 blk_info = &(g_kv_mgr.block_info[i]);
200 if ((blk_info->space) > len) {
201 blk_start = (i << KV_BLOCK_SIZE_BITS);
202 g_kv_mgr.write_pos = blk_start + KV_BLOCK_SIZE - blk_info->space;
203
204 if (blk_info->state == KV_BLOCK_STATE_CLEAN) {
205 if (kv_set_block_state(i, KV_BLOCK_STATE_USED) != KV_OK) {
206 return 0;
207 }
208 g_kv_mgr.clean_blk_nums--;
209 }
210 return g_kv_mgr.write_pos;
211 }
212 }
213 #endif
214
215 kv_trigger_gc();
216
217 return 0;
218 }
219
220 /**
221 * @brief Key-value pair item delete
222 *
223 * @param[in] item pointer to the key-value pair need to deleted
224 * @param[in] flag the flag indicate item delete request is from del or update
225 *
226 * @return 0 on success, otherwise is failed
227 */
kv_item_del(kv_item_t * item,int flag)228 static int32_t kv_item_del(kv_item_t *item, int flag)
229 {
230 uint8_t i;
231 kv_size_t off;
232 item_hdr_t hdr;
233
234 int res = KV_OK;
235 char *ori = NULL;
236 char *new = NULL;
237
238 if (flag == KV_DELETE_FLAG) {
239 off = item->pos;
240 } else if (flag == KV_UPDATE_FLAG) {
241 off = item->hdr.origin_off;
242 memset(&hdr, 0, KV_ITEM_HDR_SIZE);
243 if (kv_flash_read(off, &hdr, KV_ITEM_HDR_SIZE) != KV_OK) {
244 return KV_ERR_FLASH_READ;
245 }
246
247 if ((hdr.magic != KV_ITEM_MAGIC_NUM) || \
248 (hdr.state != KV_ITEM_STATE_NORMAL) || \
249 (hdr.key_len != item->hdr.key_len)) {
250 return KV_OK;
251 }
252
253 ori = (char *)kv_malloc(hdr.key_len);
254 if (!ori) {
255 return KV_ERR_MALLOC_FAILED;
256 }
257
258 new = (char *)kv_malloc(hdr.key_len);
259 if (!new) {
260 kv_free(ori);
261 return KV_ERR_MALLOC_FAILED;
262 }
263
264 kv_flash_read(off + KV_ITEM_HDR_SIZE, ori, hdr.key_len);
265 kv_flash_read(item->pos + KV_ITEM_HDR_SIZE, new, hdr.key_len);
266 if (memcmp(ori, new, hdr.key_len) != 0) {
267 kv_free(ori);
268 kv_free(new);
269 return KV_OK;
270 }
271
272 kv_free(ori);
273 kv_free(new);
274 } else {
275 return KV_ERR_INVALID_PARAM;
276 }
277
278 if ((res = kv_set_item_state(off, KV_ITEM_STATE_DELETE)) != KV_OK) {
279 return res;
280 }
281
282 i = off >> KV_BLOCK_SIZE_BITS;
283 if (g_kv_mgr.block_info[i].state == KV_BLOCK_STATE_USED) {
284 res = kv_set_block_state(i, KV_BLOCK_STATE_DIRTY);
285 }
286
287 return res;
288 }
289
290 /**
291 * @brief recovery callback function when polling the block
292 *
293 * @param[in] item pointer to the key-value pair item
294 * @param[in] key pointer to the key
295 *
296 * @return KV_LOOP_CONTINUE: continue to polling, otherwise is failed
297 */
__item_recovery_cb(kv_item_t * item,const char * key)298 static int32_t __item_recovery_cb(kv_item_t *item, const char *key)
299 {
300 int32_t res;
301
302 char *p = (char *)kv_malloc(item->len);
303 if (!p) {
304 return KV_ERR_MALLOC_FAILED;
305 }
306
307 res = kv_flash_read(item->pos + KV_ITEM_HDR_SIZE, p, item->len);
308 if (res != KV_OK) {
309 kv_free(p);
310 return KV_ERR_FLASH_READ;
311 }
312
313 if (item->hdr.crc == calc_crc8((uint8_t *)p, item->len)) {
314 if ((item->hdr.origin_off != 0) && \
315 (item->pos != item->hdr.origin_off)) {
316 kv_item_del(item, KV_UPDATE_FLAG);
317 }
318 } else {
319 kv_item_del(item, KV_DELETE_FLAG);
320 }
321
322 kv_free(p);
323 return KV_LOOP_CONTINUE;
324 }
325
326 /**
327 * @brief find callback function when polling the block
328 *
329 * @param[in] item pointer to the key-value pair item
330 * @param[in] key pointer to the key
331 *
332 * @return KV_OK: find the item;
333 * KV_LOOP_CONTINUE: continue to polling,
334 * otherwise is failed
335 */
__item_find_cb(kv_item_t * item,const char * key)336 static int32_t __item_find_cb(kv_item_t *item, const char *key)
337 {
338 int32_t res;
339
340 if (item->hdr.key_len != strlen(key)) {
341 return KV_LOOP_CONTINUE;
342 }
343
344 item->store = (char *)kv_malloc(item->hdr.key_len + item->hdr.val_len);
345 if (!item->store) {
346 return KV_ERR_MALLOC_FAILED;
347 }
348
349 res = kv_flash_read(item->pos + KV_ITEM_HDR_SIZE, item->store,
350 item->len);
351 if (res != KV_OK) {
352 return KV_ERR_FLASH_READ;
353 }
354
355 if (memcmp(item->store, key, strlen(key)) == 0) {
356 return KV_OK;
357 }
358
359 return KV_LOOP_CONTINUE;
360 }
361
362 /**
363 * @brief GC callback function when polling the block
364 *
365 * @param[in] item pointer to the key-value pair item
366 * @param[in] key pointer to the key
367 *
368 * @return KV_LOOP_CONTINUE: continue to polling, otherwise is failed
369 */
__item_gc_cb(kv_item_t * item,const char * key)370 static int32_t __item_gc_cb(kv_item_t *item, const char *key)
371 {
372 char *p;
373 int32_t res;
374 uint8_t idx;
375 uint16_t len;
376
377 len = KV_ALIGN(KV_ITEM_HDR_SIZE + item->len);
378
379 p = (char *)kv_malloc(len);
380 if (!p) {
381 return KV_ERR_MALLOC_FAILED;
382 }
383
384 if (kv_flash_read(item->pos, p, len) != KV_OK) {
385 res = KV_ERR_FLASH_READ;
386 goto err;
387 }
388
389 if (kv_flash_write(g_kv_mgr.write_pos, p, len) != KV_OK) {
390 res = KV_ERR_FLASH_WRITE;
391 goto err;
392 }
393
394 g_kv_mgr.write_pos += len;
395 idx = (g_kv_mgr.write_pos) >> KV_BLOCK_SIZE_BITS;
396 g_kv_mgr.block_info[idx].space -= len;
397 res = KV_LOOP_CONTINUE;
398
399 err:
400 kv_free(p);
401
402 return res;
403 }
404
405 /**
406 * @brief Group delete callback function when polling the block
407 *
408 * @param[in] item pointer to the key-value pair item
409 * @param[in] key pointer to the key
410 *
411 * @return KV_LOOP_CONTINUE: continue to polling, otherwise is failed
412 */
__item_del_by_prefix_cb(kv_item_t * item,const char * prefix)413 static int32_t __item_del_by_prefix_cb(kv_item_t *item, const char *prefix)
414 {
415 char *key = NULL;
416
417 if (prefix != NULL && item->hdr.key_len < strlen(prefix)) {
418 return KV_LOOP_CONTINUE;
419 }
420
421 key = (char *)kv_malloc(item->hdr.key_len + 1);
422 if (!key) {
423 return KV_ERR_MALLOC_FAILED;
424 }
425
426 memset(key, 0, item->hdr.key_len + 1);
427 kv_flash_read(item->pos + KV_ITEM_HDR_SIZE, key, item->hdr.key_len);
428
429 if (prefix == NULL || strncmp(key, prefix, strlen(prefix)) == 0) {
430 kv_item_del(item, KV_DELETE_FLAG);
431 }
432
433 kv_free(key);
434
435 return KV_LOOP_CONTINUE;
436 }
437
438 /**
439 * @brief Search key-value pair item
440 *
441 * @param[in] key pointer to the item key
442 *
443 * @return key-value item or NULL
444 */
kv_item_search(const char * key)445 static kv_item_t *kv_item_search(const char *key)
446 {
447 uint8_t i;
448
449 kv_item_t *item = NULL;
450
451 for (i = 0; i < KV_BLOCK_NUMS; i++) {
452 if (g_kv_mgr.block_info[i].state != KV_BLOCK_STATE_CLEAN) {
453 item = kv_item_traverse(__item_find_cb, i, key);
454 if (item != NULL) {
455 return item;
456 }
457 }
458 }
459
460 return NULL;
461 }
462
463 /**
464 * @brief Store key-value item
465 *
466 * @param[in] key pointer to the item key
467 * @param[in] val pointer to the item value
468 * @param[in] len the length of the value
469 * @param[in] origin_off the old item position offset
470 *
471 * @return 0 on success, otherwise is failed
472 */
kv_item_store(const char * key,const void * val,int len,kv_size_t origin_off)473 static int32_t kv_item_store(const char *key, const void *val, int len,
474 kv_size_t origin_off)
475 {
476 char *p;
477 uint8_t idx;
478 kv_size_t pos;
479 item_hdr_t hdr;
480 kv_store_t store;
481
482 hdr.magic = KV_ITEM_MAGIC_NUM;
483 hdr.state = KV_ITEM_STATE_NORMAL;
484 hdr.key_len = strlen(key);
485 hdr.val_len = len;
486 hdr.origin_off = origin_off;
487
488 store.len = KV_ALIGN(KV_ITEM_HDR_SIZE + hdr.key_len + hdr.val_len);
489
490 store.p = (char *)kv_malloc(store.len);
491 if (!store.p) {
492 return KV_ERR_MALLOC_FAILED;
493 }
494
495 memset(store.p, 0, store.len);
496 p = store.p + KV_ITEM_HDR_SIZE;
497
498 memcpy(p, key, hdr.key_len);
499 p += hdr.key_len;
500
501 memcpy(p, val, hdr.val_len);
502 p -= hdr.key_len;
503
504 hdr.crc = calc_crc8((uint8_t *)p, hdr.key_len + hdr.val_len);
505 memcpy(store.p, &hdr, KV_ITEM_HDR_SIZE);
506
507 pos = kv_calc_position(store.len);
508 if (pos > 0) {
509 store.res = kv_flash_write(pos, store.p, store.len);
510 if (store.res == KV_OK) {
511 g_kv_mgr.write_pos = pos + store.len;
512 idx = (uint8_t)(g_kv_mgr.write_pos >> KV_BLOCK_SIZE_BITS);
513 g_kv_mgr.block_info[idx].space -= store.len;
514 }
515 } else {
516 store.res = KV_ERR_NO_SPACE;
517 }
518
519 if (store.p) {
520 kv_free(store.p);
521 }
522
523 return store.res;
524 }
525
526 /**
527 * @brief Update the item value
528 *
529 * @param[in] item pointer to the key-value item
530 * @param[in] key pointer to the item key
531 * @param[in] val pointer to the item value
532 * @param[in] len the length of the item value
533 *
534 * @return 0 on success, otherwise is failed
535 */
kv_item_update(kv_item_t * item,const char * key,const void * val,int32_t len)536 static int32_t kv_item_update(kv_item_t *item, const char *key, const void *val,
537 int32_t len)
538 {
539 int res;
540
541 if (item->hdr.val_len == len) {
542 if (!memcmp(item->store + item->hdr.key_len, val, len)) {
543 return KV_OK;
544 }
545 }
546
547 res = kv_item_store(key, val, len, item->pos);
548 if (res != KV_OK) {
549 return res;
550 }
551
552 res = kv_item_del(item, KV_DELETE_FLAG);
553
554 return res;
555 }
556
557 /**
558 * @brief Initialize the KV module
559 *
560 * @return 0 on success, otherwise is failed
561 */
kv_init_internal(void)562 static int32_t kv_init_internal(void)
563 {
564 uint8_t i;
565 uint8_t next;
566 block_hdr_t hdr;
567
568 int32_t res = KV_OK;
569 int32_t nums = 0;
570
571 uint8_t unclean[KV_BLOCK_NUMS] = {0};
572
573 for (i = 0; i < KV_BLOCK_NUMS; i++) {
574 memset(&hdr, 0, KV_BLOCK_HDR_SIZE);
575 kv_flash_read((i << KV_BLOCK_SIZE_BITS), &hdr, KV_BLOCK_HDR_SIZE);
576 if (hdr.magic == KV_BLOCK_MAGIC_NUM) {
577 if (INVALID_BLK_STATE(hdr.state)) {
578 if ((res = kv_block_format(i)) != KV_OK) {
579 return res;
580 } else {
581 continue;
582 }
583 }
584
585 g_kv_mgr.block_info[i].state = hdr.state;
586 kv_item_traverse(__item_recovery_cb, i, NULL);
587 if (hdr.state == KV_BLOCK_STATE_CLEAN) {
588 if (g_kv_mgr.block_info[i].space != (KV_BLOCK_SIZE - KV_BLOCK_HDR_SIZE)) {
589 unclean[nums] = i;
590 nums++;
591 } else {
592 g_kv_mgr.clean_blk_nums++;
593 }
594 }
595 } else {
596 if ((res = kv_block_format(i)) != KV_OK) {
597 return res;
598 }
599 }
600 }
601
602 while (nums > 0) {
603 i = unclean[nums - 1];
604 if (g_kv_mgr.clean_blk_nums >= KV_RESERVED_BLOCKS) {
605 res = kv_set_block_state(i, KV_BLOCK_STATE_DIRTY);
606 if (res != KV_OK) {
607 return res;
608 }
609 } else {
610 if ((res = kv_block_format(i)) != KV_OK) {
611 return res;
612 }
613 }
614 nums--;
615 }
616
617 if (g_kv_mgr.clean_blk_nums == 0) {
618 if ((res = kv_block_format(0)) != KV_OK) {
619 return res;
620 }
621 }
622
623 if (g_kv_mgr.clean_blk_nums == KV_BLOCK_NUMS) {
624 g_kv_mgr.write_pos = KV_BLOCK_HDR_SIZE;
625 i = (uint8_t)(g_kv_mgr.write_pos & KV_BLOCK_OFF_MASK);
626
627 res = kv_set_block_state(i, KV_BLOCK_STATE_USED);
628 if (res != KV_OK) {
629 return res;
630 }
631 g_kv_mgr.clean_blk_nums--;
632 } else {
633 for (i = 0; i < KV_BLOCK_NUMS; i++) {
634 if ((g_kv_mgr.block_info[i].state == KV_BLOCK_STATE_USED) || \
635 (g_kv_mgr.block_info[i].state == KV_BLOCK_STATE_DIRTY)) {
636 next = ((i + 1) == KV_BLOCK_NUMS) ? 0 : (i + 1);
637 if (g_kv_mgr.block_info[next].state == KV_BLOCK_STATE_CLEAN) {
638 g_kv_mgr.write_pos = (i << KV_BLOCK_SIZE_BITS) + \
639 KV_BLOCK_SIZE - \
640 g_kv_mgr.block_info[i].space;
641 break;
642 }
643 }
644 }
645 }
646
647 return KV_OK;
648 }
649
650 /**
651 * Garbage collection task
652 *
653 * @param[in] arg pointer to the argument
654 *
655 * @return none
656 */
kv_gc_task(void * arg)657 static void kv_gc_task(void *arg)
658 {
659 kv_size_t origin_pos;
660 uint8_t i;
661 uint8_t gc_idx;
662
663 uint8_t gc_copy = 0;
664
665 if ((kv_lock(g_kv_mgr.lock)) != KV_OK) {
666 goto exit;
667 }
668
669 origin_pos = g_kv_mgr.write_pos;
670 if (g_kv_mgr.clean_blk_nums == 0) {
671 goto exit;
672 }
673
674 for (gc_idx = 0; gc_idx < KV_BLOCK_NUMS; gc_idx++) {
675 if (g_kv_mgr.block_info[gc_idx].state == KV_BLOCK_STATE_CLEAN) {
676 g_kv_mgr.write_pos = (gc_idx << KV_BLOCK_SIZE_BITS) + KV_BLOCK_HDR_SIZE;
677 break;
678 }
679 }
680
681 if (gc_idx == KV_BLOCK_NUMS) {
682 goto exit;
683 }
684
685 i = (origin_pos >> KV_BLOCK_SIZE_BITS) + 1;
686 while (1) {
687 if (i == KV_BLOCK_NUMS) {
688 i = 0;
689 }
690
691 if (g_kv_mgr.block_info[i].state == KV_BLOCK_STATE_DIRTY) {
692 kv_item_traverse(__item_gc_cb, i, NULL);
693
694 gc_copy = 1;
695
696 if (kv_block_format(i) != KV_OK) {
697 goto exit;
698 }
699
700 kv_set_block_state(gc_idx, KV_BLOCK_STATE_USED);
701 g_kv_mgr.clean_blk_nums--;
702 break;
703 }
704
705 if (i == (origin_pos >> KV_BLOCK_SIZE_BITS)) {
706 break;
707 }
708 i++;
709 }
710
711 if (gc_copy == 0) {
712 g_kv_mgr.write_pos = origin_pos;
713 }
714
715 exit:
716 g_kv_mgr.gc_trigger = 0;
717 kv_unlock(g_kv_mgr.lock);
718 if (g_kv_mgr.gc_waiter > 0) {
719 kv_sem_post_all(g_kv_mgr.gc_sem);
720 }
721
722 kv_delete_task();
723 }
724
725 /**
726 * @brief polling flash block
727 *
728 * @param[in] func pointer to callback function
729 * @param[in] blk_idx the block index
730 * @param[in] key pointer to the key
731 *
732 * @return the key-value item or NULL.
733 */
kv_item_traverse(item_func func,uint8_t blk_idx,const char * key)734 kv_item_t *kv_item_traverse(item_func func, uint8_t blk_idx, const char *key)
735 {
736 int32_t res;
737 uint16_t len;
738 kv_size_t pos;
739 kv_size_t end;
740 kv_item_t *item;
741 item_hdr_t *hdr;
742
743 pos = (blk_idx << KV_BLOCK_SIZE_BITS) + KV_BLOCK_HDR_SIZE;
744 end = (blk_idx << KV_BLOCK_SIZE_BITS) + KV_BLOCK_SIZE;
745 len = 0;
746
747 do {
748 item = (kv_item_t *)kv_malloc(sizeof(kv_item_t));
749 if (!item) {
750 return NULL;
751 }
752
753 memset(item, 0, sizeof(kv_item_t));
754 hdr = &(item->hdr);
755
756 if (kv_flash_read(pos, hdr, KV_ITEM_HDR_SIZE) != KV_OK) {
757 kv_item_free(item);
758 return NULL;
759 }
760
761 if (hdr->magic != KV_ITEM_MAGIC_NUM) {
762 if ((hdr->magic == 0xFF) && (hdr->state == 0xFF)) {
763 kv_item_free(item);
764 break;
765 }
766 hdr->val_len = 0xFFFF;
767 }
768
769 if ((hdr->val_len > KV_MAX_VAL_LEN) || \
770 (hdr->key_len > KV_MAX_KEY_LEN) || \
771 (hdr->val_len == 0) || (hdr->key_len == 0)) {
772
773 pos += KV_ITEM_HDR_SIZE;
774 kv_item_free(item);
775
776 if (g_kv_mgr.block_info[blk_idx].state == KV_BLOCK_STATE_USED) {
777 kv_set_block_state(blk_idx, KV_BLOCK_STATE_DIRTY);
778 }
779 continue;
780 }
781
782 len = KV_ALIGN(KV_ITEM_HDR_SIZE + hdr->key_len + hdr->val_len);
783
784 if (hdr->state == KV_ITEM_STATE_NORMAL) {
785 item->pos = pos;
786 item->len = hdr->key_len + hdr->val_len;
787
788 res = func(item, key);
789 if (res == KV_OK) {
790 return item;
791 } else if (res != KV_LOOP_CONTINUE) {
792 kv_item_free(item);
793 return NULL;
794 }
795 } else {
796 if (g_kv_mgr.block_info[blk_idx].state == KV_BLOCK_STATE_USED) {
797 kv_set_block_state(blk_idx, KV_BLOCK_STATE_DIRTY);
798 }
799 }
800
801 kv_item_free(item);
802 pos += len;
803 } while (end > (pos + KV_ITEM_HDR_SIZE));
804
805 if (end > pos) {
806 g_kv_mgr.block_info[blk_idx].space = end - pos;
807 } else {
808 g_kv_mgr.block_info[blk_idx].space = KV_ITEM_HDR_SIZE;
809 }
810
811 return NULL;
812 }
813
814 /******************************************************/
815 /****************** Public Interface ******************/
816 /******************************************************/
817
kv_init(void)818 int32_t kv_init(void)
819 {
820 int32_t res;
821 uint8_t blk_idx;
822
823 if (g_kv_mgr.inited) {
824 return KV_OK;
825 }
826
827 if (KV_BLOCK_NUMS <= KV_RESERVED_BLOCKS) {
828 return KV_ERR_INVALID_PARAM;
829 }
830
831 memset(&g_kv_mgr, 0, sizeof(kv_mgr_t));
832
833 g_kv_mgr.lock = kv_lock_create();
834 if (g_kv_mgr.lock == NULL) {
835 return KV_ERR_OS_LOCK;
836 }
837
838 g_kv_mgr.gc_sem = kv_sem_create();
839 if (g_kv_mgr.gc_sem == NULL) {
840 return KV_ERR_OS_SEM;
841 }
842
843 if ((res = kv_init_internal()) != KV_OK) {
844 return res;
845 }
846
847 g_kv_mgr.inited = 1;
848
849 blk_idx = (g_kv_mgr.write_pos >> KV_BLOCK_SIZE_BITS);
850 if (((g_kv_mgr.block_info[blk_idx].space) < KV_ITEM_MAX_LEN) && \
851 (g_kv_mgr.clean_blk_nums < KV_RESERVED_BLOCKS + 1)) {
852 kv_trigger_gc();
853 }
854 #if AOS_COMP_CLI
855 extern void kv_register_cli_command(void);
856 kv_register_cli_command();
857 #endif
858
859 return KV_OK;
860 }
861
kv_deinit(void)862 void kv_deinit(void)
863 {
864 g_kv_mgr.inited = 0;
865
866 kv_sem_free(g_kv_mgr.gc_sem);
867
868 kv_lock_free(g_kv_mgr.lock);
869 }
870
kv_item_set(const char * key,const void * val,int32_t len)871 int32_t kv_item_set(const char *key, const void *val, int32_t len)
872 {
873 int32_t res;
874
875 kv_item_t *item = NULL;
876
877 #if (KV_SECURE_SUPPORT) && (KV_SECURE_LEVEL > 1)
878 return kv_item_secure_set(key, val, len);
879 #endif
880
881 if (!key || !val || (len <= 0) || (strlen(key) > KV_MAX_KEY_LEN) || \
882 (len > KV_MAX_VAL_LEN)) {
883 return KV_ERR_INVALID_PARAM;
884 }
885
886 if (g_kv_mgr.gc_trigger != 0) {
887 g_kv_mgr.gc_waiter++;
888 kv_sem_wait(g_kv_mgr.gc_sem);
889 }
890
891 if ((res = kv_lock(g_kv_mgr.lock)) != KV_OK) {
892 return KV_ERR_OS_LOCK;
893 }
894
895 item = kv_item_search(key);
896 if (item != NULL) {
897 res = kv_item_update(item, key, val, len);
898 kv_item_free(item);
899 } else {
900 res = kv_item_store(key, val, len, 0);
901 }
902
903 kv_unlock(g_kv_mgr.lock);
904
905 return res;
906 }
907
kv_item_get(const char * key,void * buffer,int32_t * buffer_len)908 int32_t kv_item_get(const char *key, void *buffer, int32_t *buffer_len)
909 {
910 kv_item_t *item = NULL;
911
912 #if (KV_SECURE_SUPPORT) && (KV_SECURE_LEVEL > 1)
913 return kv_item_secure_get(key, buffer, buffer_len);
914 #endif
915
916 if (!key || !buffer || !buffer_len || (*buffer_len <= 0)) {
917 return KV_ERR_INVALID_PARAM;
918 }
919
920 if ((kv_lock(g_kv_mgr.lock)) != KV_OK) {
921 return KV_ERR_OS_LOCK;
922 }
923
924 item = kv_item_search(key);
925
926 kv_unlock(g_kv_mgr.lock);
927
928 if (!item) {
929 return KV_ERR_NOT_FOUND;
930 }
931
932 if (*buffer_len < item->hdr.val_len) {
933 *buffer_len = item->hdr.val_len;
934 kv_item_free(item);
935 return KV_ERR_NO_SPACE;
936 } else {
937 memcpy(buffer, (item->store + item->hdr.key_len), item->hdr.val_len);
938 *buffer_len = item->hdr.val_len;
939 }
940
941 kv_item_free(item);
942
943 return KV_OK;
944 }
945
kv_item_delete(const char * key)946 int32_t kv_item_delete(const char *key)
947 {
948 int32_t res;
949
950 kv_item_t *item = NULL;
951
952 if ((res = kv_lock(g_kv_mgr.lock)) != KV_OK) {
953 return KV_ERR_OS_LOCK;
954 }
955
956 item = kv_item_search(key);
957 if (!item) {
958 kv_unlock(g_kv_mgr.lock);
959 return KV_ERR_NOT_FOUND;
960 }
961
962 res = kv_item_del(item, KV_DELETE_FLAG);
963 kv_item_free(item);
964 kv_unlock(g_kv_mgr.lock);
965
966 return res;
967 }
968
kv_item_delete_by_prefix(const char * prefix)969 int32_t kv_item_delete_by_prefix(const char *prefix)
970 {
971 int32_t i;
972
973 if ((kv_lock(g_kv_mgr.lock)) != KV_OK) {
974 return KV_ERR_OS_LOCK;
975 }
976
977 for (i = 0; i < KV_BLOCK_NUMS; i++) {
978 kv_item_traverse(__item_del_by_prefix_cb, i, prefix);
979 }
980
981 kv_unlock(g_kv_mgr.lock);
982
983 return KV_OK;
984 }
985
986 #if (KV_SECURE_SUPPORT)
987
kv_item_secure_set(const char * key,const void * val,int32_t len)988 int32_t kv_item_secure_set(const char *key, const void *val, int32_t len)
989 {
990 int32_t res;
991
992 uint8_t *data = NULL;
993 kv_item_t *item = NULL;
994
995 if (!key || !val || (len <= 0) || (strlen(key) > KV_MAX_KEY_LEN) || \
996 (len > KV_MAX_VAL_LEN)) {
997 return KV_ERR_INVALID_PARAM;
998 }
999
1000 if (g_kv_mgr.gc_trigger != 0) {
1001 g_kv_mgr.gc_waiter++;
1002 kv_sem_wait(g_kv_mgr.gc_sem);
1003 }
1004
1005 if ((res = kv_lock(g_kv_mgr.lock)) != KV_OK) {
1006 return KV_ERR_OS_LOCK;
1007 }
1008
1009 data = (uint8_t *)kv_malloc(len);
1010 if (data == NULL) {
1011 return KV_ERR_NO_SPACE;
1012 }
1013
1014 memset(data, 0, len);
1015
1016 res = kv_secure_encrypt((uint8_t *)val, data, len);
1017 if (res != KV_OK) {
1018 kv_free(data);
1019 data = NULL;
1020
1021 return KV_ERR_ENCRYPT;
1022 }
1023
1024 item = kv_item_search(key);
1025 if (item != NULL) {
1026 res = kv_item_update(item, key, data, len);
1027 kv_item_free(item);
1028
1029 } else {
1030 res = kv_item_store(key, data, len, 0);
1031 }
1032
1033 kv_unlock(g_kv_mgr.lock);
1034
1035 kv_free(data);
1036 data = NULL;
1037
1038 return res;
1039 }
1040
kv_item_secure_get(const char * key,void * buffer,int32_t * buffer_len)1041 int32_t kv_item_secure_get(const char *key, void *buffer, int32_t *buffer_len)
1042 {
1043 int32_t res;
1044
1045 uint8_t *data = NULL;
1046 kv_item_t *item = NULL;
1047
1048 if (!key || !buffer || !buffer_len || (*buffer_len <= 0)) {
1049 return KV_ERR_INVALID_PARAM;
1050 }
1051
1052 if ((res = kv_lock(g_kv_mgr.lock)) != KV_OK) {
1053 return KV_ERR_OS_LOCK;
1054 }
1055
1056 item = kv_item_search(key);
1057
1058 kv_unlock(g_kv_mgr.lock);
1059
1060 if (!item) {
1061 return KV_ERR_NOT_FOUND;
1062 }
1063
1064 if (*buffer_len < item->hdr.val_len) {
1065 *buffer_len = item->hdr.val_len;
1066 kv_item_free(item);
1067 return KV_ERR_NO_SPACE;
1068 } else {
1069 data = (uint8_t *)kv_malloc(item->hdr.val_len);
1070 if (data == NULL) {
1071 return KV_ERR_NO_SPACE;
1072 }
1073
1074 memset(data, 0, item->hdr.val_len);
1075
1076 res = kv_secure_decrypt((uint8_t *)(item->store + item->hdr.key_len), data, item->hdr.val_len);
1077 if (res != KV_OK) {
1078 kv_free(data);
1079 data = NULL;
1080
1081 return KV_ERR_DECRYPT;
1082 }
1083
1084 memcpy(buffer, data, item->hdr.val_len);
1085 *buffer_len = item->hdr.val_len;
1086 }
1087
1088 kv_item_free(item);
1089
1090 kv_free(data);
1091 data = NULL;
1092
1093 return KV_OK;
1094 }
1095
1096 #else
kv_item_secure_set(const char * key,const void * val,int32_t len)1097 int32_t kv_item_secure_set(const char *key, const void *val, int32_t len)
1098 {
1099 return KV_ERR_NOT_SUPPORT;
1100 }
1101
kv_item_secure_get(const char * key,void * buffer,int32_t * buffer_len)1102 int32_t kv_item_secure_get(const char *key, void *buffer, int32_t *buffer_len)
1103 {
1104 return KV_ERR_NOT_SUPPORT;
1105 }
1106 #endif
1107
1108