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