mirror of
https://gitee.com/Armink/EasyFlash.git
synced 2024-11-29 18:57:41 +08:00
【增加】扇区缓存功能。
Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
parent
6d1797c7a7
commit
6ba7d062f5
@ -64,6 +64,20 @@
|
|||||||
#define EF_GC_EMPTY_SEC_THRESHOLD 1
|
#define EF_GC_EMPTY_SEC_THRESHOLD 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* the ENV cache table size, it will improve ENV search speed when using cache */
|
||||||
|
#ifndef EF_ENV_CACHE_TABLE_SIZE
|
||||||
|
#define EF_ENV_CACHE_TABLE_SIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the sector cache table size, it will improve ENV save speed when using cache */
|
||||||
|
#ifndef EF_SECTOR_CACHE_TABLE_SIZE
|
||||||
|
#define EF_SECTOR_CACHE_TABLE_SIZE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (EF_ENV_CACHE_TABLE_SIZE > 0) && (EF_SECTOR_CACHE_TABLE_SIZE > 0)
|
||||||
|
#define EF_ENV_USING_CACHE
|
||||||
|
#endif
|
||||||
|
|
||||||
/* the sector is not combined value */
|
/* the sector is not combined value */
|
||||||
#define SECTOR_NOT_COMBINED 0xFFFFFFFF
|
#define SECTOR_NOT_COMBINED 0xFFFFFFFF
|
||||||
/* the next address is get failed */
|
/* the next address is get failed */
|
||||||
@ -110,6 +124,8 @@
|
|||||||
#define ENV_LEN_OFFSET ((unsigned long)(&((struct env_hdr_data *)0)->len))
|
#define ENV_LEN_OFFSET ((unsigned long)(&((struct env_hdr_data *)0)->len))
|
||||||
#define ENV_NAME_LEN_OFFSET ((unsigned long)(&((struct env_hdr_data *)0)->name_len))
|
#define ENV_NAME_LEN_OFFSET ((unsigned long)(&((struct env_hdr_data *)0)->name_len))
|
||||||
|
|
||||||
|
//#define ADDR_IS_SECTOR_HDR(addr) (addr % SECTOR_SIZE == 0)
|
||||||
|
|
||||||
#define VER_NUM_ENV_NAME "__ver_num__"
|
#define VER_NUM_ENV_NAME "__ver_num__"
|
||||||
|
|
||||||
enum sector_store_status {
|
enum sector_store_status {
|
||||||
@ -189,6 +205,19 @@ struct env_meta_data {
|
|||||||
};
|
};
|
||||||
typedef struct env_meta_data *env_meta_data_t;
|
typedef struct env_meta_data *env_meta_data_t;
|
||||||
|
|
||||||
|
struct env_cache_node {
|
||||||
|
uint16_t name_crc; /**< ENV name's CRC32 low 16bit value */
|
||||||
|
uint16_t activity; /**< ENV node access activity degree */
|
||||||
|
uint32_t addr; /**< ENV node address */
|
||||||
|
};
|
||||||
|
typedef struct env_cache_node *env_cache_node_t;
|
||||||
|
|
||||||
|
struct sector_cache_node {
|
||||||
|
uint32_t addr; /**< sector start address */
|
||||||
|
uint32_t empty_addr; /**< sector empty address */
|
||||||
|
};
|
||||||
|
typedef struct sector_cache_node *sector_cache_node_t;
|
||||||
|
|
||||||
static void gc_collect(void);
|
static void gc_collect(void);
|
||||||
|
|
||||||
/* ENV start address in flash */
|
/* ENV start address in flash */
|
||||||
@ -202,6 +231,13 @@ static bool init_ok = false;
|
|||||||
/* request a GC check */
|
/* request a GC check */
|
||||||
static bool gc_request = false;
|
static bool gc_request = false;
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
/* ENV cache table */
|
||||||
|
struct env_cache_node env_cache_table[EF_ENV_CACHE_TABLE_SIZE] = { 0 };
|
||||||
|
/* sector cache table, it caching the sector info which status is current using */
|
||||||
|
struct sector_cache_node sector_cache_table[EF_SECTOR_CACHE_TABLE_SIZE] = { 0 };
|
||||||
|
#endif /* EF_ENV_USING_CACHE */
|
||||||
|
|
||||||
static size_t set_status(uint8_t status_table[], size_t status_num, size_t status_index)
|
static size_t set_status(uint8_t status_table[], size_t status_num, size_t status_index)
|
||||||
{
|
{
|
||||||
size_t byte_index = ~0UL;
|
size_t byte_index = ~0UL;
|
||||||
@ -255,6 +291,8 @@ static EfErrCode write_status(uint32_t addr, uint8_t status_table[], size_t stat
|
|||||||
EF_ASSERT(status_index < status_num);
|
EF_ASSERT(status_index < status_num);
|
||||||
EF_ASSERT(status_table);
|
EF_ASSERT(status_table);
|
||||||
|
|
||||||
|
//TODO 完善写状态 API,扇区 cache 可否在这里更新
|
||||||
|
|
||||||
/* set the status first */
|
/* set the status first */
|
||||||
byte_index = set_status(status_table, status_num, status_index);
|
byte_index = set_status(status_table, status_num, status_index);
|
||||||
|
|
||||||
@ -277,16 +315,74 @@ static size_t read_status(uint32_t addr, uint8_t status_table[], size_t total_nu
|
|||||||
{
|
{
|
||||||
EF_ASSERT(status_table);
|
EF_ASSERT(status_table);
|
||||||
|
|
||||||
|
//TODO 完善读状态 API,扇区 cache 可否在这里更新
|
||||||
|
|
||||||
ef_port_read(addr, (uint32_t *) status_table, STATUS_TABLE_SIZE(total_num));
|
ef_port_read(addr, (uint32_t *) status_table, STATUS_TABLE_SIZE(total_num));
|
||||||
|
|
||||||
return get_status(status_table, total_num);
|
return get_status(status_table, total_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
/*
|
||||||
|
* It's only caching the current using status sector's empty_addr
|
||||||
|
*/
|
||||||
|
static void update_sector_cache(uint32_t sec_addr, uint32_t empty_addr)
|
||||||
|
{
|
||||||
|
size_t i, empty_index = EF_SECTOR_CACHE_TABLE_SIZE;
|
||||||
|
|
||||||
|
for (i = 0; i < EF_SECTOR_CACHE_TABLE_SIZE; i++) {
|
||||||
|
if ((empty_addr > sec_addr) && (empty_addr < sec_addr + SECTOR_SIZE)) {
|
||||||
|
/* update the sector empty_addr in cache */
|
||||||
|
if (sector_cache_table[i].addr == sec_addr) {
|
||||||
|
EF_DEBUG("Update sector(%p) empty_addr: %p in cache %d\n", sec_addr, empty_addr, i);
|
||||||
|
sector_cache_table[i].addr = sec_addr;
|
||||||
|
sector_cache_table[i].empty_addr = empty_addr;
|
||||||
|
return;
|
||||||
|
} else if ((sector_cache_table[i].addr == FAILED_ADDR) && (empty_index == EF_SECTOR_CACHE_TABLE_SIZE)) {
|
||||||
|
empty_index = i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* delete the sector which status is not current using */
|
||||||
|
if (sector_cache_table[i].addr == sec_addr) {
|
||||||
|
sector_cache_table[i].addr = FAILED_ADDR;
|
||||||
|
EF_DEBUG("Delete sector(%p) empty_addr: %p in cache %d\n", sec_addr, sector_cache_table[i].empty_addr, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* add the sector empty_addr to cache */
|
||||||
|
if (empty_index < EF_SECTOR_CACHE_TABLE_SIZE) {
|
||||||
|
EF_DEBUG("Add sector(%p) empty_addr: %p in cache %d\n", sec_addr, empty_addr, empty_index);
|
||||||
|
sector_cache_table[empty_index].addr = sec_addr;
|
||||||
|
sector_cache_table[empty_index].empty_addr = empty_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get sector info from cache. It's return true when cache is hit.
|
||||||
|
*/
|
||||||
|
static bool get_sector_from_cache(uint32_t sec_addr, uint32_t *empty_addr)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < EF_SECTOR_CACHE_TABLE_SIZE; i++) {
|
||||||
|
if (sector_cache_table[i].addr == sec_addr) {
|
||||||
|
*empty_addr = sector_cache_table[i].empty_addr;
|
||||||
|
EF_DEBUG("Get sector(%p) empty_addr: %p in cache %d\n", sec_addr, *empty_addr, i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif /* EF_ENV_USING_CACHE */
|
||||||
|
|
||||||
static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre_env)
|
static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre_env)
|
||||||
{
|
{
|
||||||
uint8_t status_table[ENV_STATUS_TABLE_SIZE];
|
uint8_t status_table[ENV_STATUS_TABLE_SIZE];
|
||||||
uint32_t addr = FAILED_ADDR;
|
uint32_t addr = FAILED_ADDR;
|
||||||
|
|
||||||
|
//TODO 通过扇区缓存获取状态
|
||||||
|
|
||||||
if (sector->status.store == SECTOR_STORE_EMPTY) {
|
if (sector->status.store == SECTOR_STORE_EMPTY) {
|
||||||
return FAILED_ADDR;
|
return FAILED_ADDR;
|
||||||
}
|
}
|
||||||
@ -405,6 +501,14 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector,
|
|||||||
sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE;
|
sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE;
|
||||||
} else if (sector->status.store == SECTOR_STORE_USING) {
|
} else if (sector->status.store == SECTOR_STORE_USING) {
|
||||||
struct env_meta_data env_meta;
|
struct env_meta_data env_meta;
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
if (get_sector_from_cache(addr, §or->empty_env)) {
|
||||||
|
sector->remain = SECTOR_SIZE - (sector->empty_env - sector->addr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* EF_ENV_USING_CACHE */
|
||||||
|
|
||||||
sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE;
|
sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE;
|
||||||
env_meta.addr.start = FAILED_ADDR;
|
env_meta.addr.start = FAILED_ADDR;
|
||||||
while ((env_meta.addr.start = get_next_env_addr(sector, &env_meta)) != FAILED_ADDR) {
|
while ((env_meta.addr.start = get_next_env_addr(sector, &env_meta)) != FAILED_ADDR) {
|
||||||
@ -628,6 +732,11 @@ static EfErrCode format_sector(uint32_t addr, uint32_t combined_value)
|
|||||||
sec_hdr.reserved = 0xFFFFFFFF;
|
sec_hdr.reserved = 0xFFFFFFFF;
|
||||||
/* save the header */
|
/* save the header */
|
||||||
result = ef_port_write(addr, (uint32_t *)&sec_hdr, sizeof(struct sector_hdr_data));
|
result = ef_port_write(addr, (uint32_t *)&sec_hdr, sizeof(struct sector_hdr_data));
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
/* delete the sector cache */
|
||||||
|
update_sector_cache(addr, addr + SECTOR_SIZE);
|
||||||
|
#endif /* EF_ENV_USING_CACHE */
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -641,11 +750,13 @@ static EfErrCode update_sec_status(sector_meta_data_t sector, size_t new_env_len
|
|||||||
if (sector->status.store == SECTOR_STORE_EMPTY) {
|
if (sector->status.store == SECTOR_STORE_EMPTY) {
|
||||||
/* change the sector status to using */
|
/* change the sector status to using */
|
||||||
result = write_status(sector->addr, status_table, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_USING);
|
result = write_status(sector->addr, status_table, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_USING);
|
||||||
|
//TODO 更新扇区 cache
|
||||||
} else if (sector->status.store == SECTOR_STORE_USING) {
|
} else if (sector->status.store == SECTOR_STORE_USING) {
|
||||||
/* check remain size */
|
/* check remain size */
|
||||||
if (sector->remain < EF_SEC_REMAIN_THRESHOLD || sector->remain - new_env_len < EF_SEC_REMAIN_THRESHOLD) {
|
if (sector->remain < EF_SEC_REMAIN_THRESHOLD || sector->remain - new_env_len < EF_SEC_REMAIN_THRESHOLD) {
|
||||||
/* change the sector status to full */
|
/* change the sector status to full */
|
||||||
result = write_status(sector->addr, status_table, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_FULL);
|
result = write_status(sector->addr, status_table, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_FULL);
|
||||||
|
//TODO 更新扇区 cache
|
||||||
if (is_full) {
|
if (is_full) {
|
||||||
*is_full = true;
|
*is_full = true;
|
||||||
}
|
}
|
||||||
@ -713,6 +824,9 @@ static uint32_t alloc_env(sector_meta_data_t sector, size_t env_size)
|
|||||||
uint32_t empty_env = FAILED_ADDR;
|
uint32_t empty_env = FAILED_ADDR;
|
||||||
size_t empty_sector = 0, using_sector = 0;
|
size_t empty_sector = 0, using_sector = 0;
|
||||||
|
|
||||||
|
//TODO 优先使用 cache
|
||||||
|
//TODO Cache 中不够了再去 empty flash 中申请
|
||||||
|
|
||||||
/* sector status statistics */
|
/* sector status statistics */
|
||||||
sector_iterator(sector, SECTOR_STORE_UNUSED, &empty_sector, &using_sector, sector_statistics_cb, false);
|
sector_iterator(sector, SECTOR_STORE_UNUSED, &empty_sector, &using_sector, sector_statistics_cb, false);
|
||||||
if (using_sector > 0) {
|
if (using_sector > 0) {
|
||||||
@ -887,6 +1001,8 @@ static bool do_gc(sector_meta_data_t sector, void *arg1, void *arg2)
|
|||||||
EF_DEBUG("Collect a sector @0x%08X\n", sector->addr);
|
EF_DEBUG("Collect a sector @0x%08X\n", sector->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO 更新全部扇区 cache
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,6 +1081,13 @@ static EfErrCode create_env_blob(sector_meta_data_t sector, const char *key, con
|
|||||||
/* update the sector status */
|
/* update the sector status */
|
||||||
if (result == EF_NO_ERR) {
|
if (result == EF_NO_ERR) {
|
||||||
result = update_sec_status(sector, env_hdr.len, &is_full);
|
result = update_sec_status(sector, env_hdr.len, &is_full);
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
if (is_full) {
|
||||||
|
/* delete the sector cache */
|
||||||
|
update_sector_cache(sector->addr, sector->addr + SECTOR_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (result == EF_NO_ERR) {
|
if (result == EF_NO_ERR) {
|
||||||
uint8_t ff = 0xFF;
|
uint8_t ff = 0xFF;
|
||||||
@ -982,10 +1105,16 @@ static EfErrCode create_env_blob(sector_meta_data_t sector, const char *key, con
|
|||||||
}
|
}
|
||||||
/* write ENV header data */
|
/* write ENV header data */
|
||||||
result = write_env_hdr(env_addr, &env_hdr);
|
result = write_env_hdr(env_addr, &env_hdr);
|
||||||
|
|
||||||
}
|
}
|
||||||
/* write key name */
|
/* write key name */
|
||||||
if (result == EF_NO_ERR) {
|
if (result == EF_NO_ERR) {
|
||||||
result = align_write(env_addr + ENV_HDR_DATA_SIZE, (uint32_t *) key, env_hdr.name_len);
|
result = align_write(env_addr + ENV_HDR_DATA_SIZE, (uint32_t *) key, env_hdr.name_len);
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
update_sector_cache(sector->addr,
|
||||||
|
env_addr + ENV_HDR_DATA_SIZE + EF_WG_ALIGN(env_hdr.name_len) + EF_WG_ALIGN(env_hdr.value_len));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
/* write value */
|
/* write value */
|
||||||
if (result == EF_NO_ERR) {
|
if (result == EF_NO_ERR) {
|
||||||
@ -1319,6 +1448,10 @@ static void env_auto_update(void)
|
|||||||
|
|
||||||
static bool check_sec_hdr_cb(sector_meta_data_t sector, void *arg1, void *arg2)
|
static bool check_sec_hdr_cb(sector_meta_data_t sector, void *arg1, void *arg2)
|
||||||
{
|
{
|
||||||
|
if (sector->check_ok && sector->status.store == SECTOR_STORE_USING) {
|
||||||
|
//TODO 更新扇区 cache
|
||||||
|
}
|
||||||
|
|
||||||
if (!sector->check_ok) {
|
if (!sector->check_ok) {
|
||||||
EF_INFO("Warning: Sector header check failed. Set it to default.\n");
|
EF_INFO("Warning: Sector header check failed. Set it to default.\n");
|
||||||
ef_port_env_unlock();
|
ef_port_env_unlock();
|
||||||
@ -1400,6 +1533,10 @@ __retry:
|
|||||||
EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) {
|
EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) {
|
||||||
EfErrCode result = EF_NO_ERR;
|
EfErrCode result = EF_NO_ERR;
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
size_t i;
|
||||||
|
#endif
|
||||||
|
|
||||||
EF_ASSERT(default_env);
|
EF_ASSERT(default_env);
|
||||||
EF_ASSERT(ENV_AREA_SIZE);
|
EF_ASSERT(ENV_AREA_SIZE);
|
||||||
/* must be aligned with erase_min_size */
|
/* must be aligned with erase_min_size */
|
||||||
@ -1413,6 +1550,12 @@ EfErrCode ef_env_init(ef_env const *default_env, size_t default_env_size) {
|
|||||||
return EF_NO_ERR;
|
return EF_NO_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EF_ENV_USING_CACHE
|
||||||
|
for (i = 0; i < EF_SECTOR_CACHE_TABLE_SIZE; i++) {
|
||||||
|
sector_cache_table[i].addr = FAILED_ADDR;
|
||||||
|
}
|
||||||
|
#endif /* EF_ENV_USING_CACHE */
|
||||||
|
|
||||||
env_start_addr = EF_START_ADDR;
|
env_start_addr = EF_START_ADDR;
|
||||||
default_env_set = default_env;
|
default_env_set = default_env;
|
||||||
default_env_set_size = default_env_size;
|
default_env_set_size = default_env_size;
|
||||||
|
Loading…
Reference in New Issue
Block a user