Skip to content

Commit 72a7905

Browse files
committed
[kvdb] Improve the GC algorithm to solve the problem of failure to collection in some cases.
1 parent 92ed442 commit 72a7905

File tree

2 files changed

+258
-45
lines changed

2 files changed

+258
-45
lines changed

src/fdb_kvdb.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#define SECTOR_MAGIC_WORD 0x30424446
3636
/* magic word(`K`, `V`, `0`, `0`) */
3737
#define KV_MAGIC_WORD 0x3030564B
38+
/* GC minimum number of empty sectors. GC will using at least 1 empty sector. */
39+
#define GC_MIN_EMPTY_SEC_NUM 1
3840

3941
/* the sector remain threshold before full status */
4042
#ifndef FDB_SEC_REMAIN_THRESHOLD
@@ -135,9 +137,8 @@ struct alloc_kv_cb_args {
135137

136138
struct gc_cb_args {
137139
fdb_kvdb_t db;
138-
size_t cur_free_size;
139140
size_t setting_free_size;
140-
uint32_t traversed_len;
141+
size_t last_gc_sec_addr;
141142
};
142143

143144
static void gc_collect(fdb_kvdb_t db);
@@ -1071,7 +1072,7 @@ static uint32_t new_kv(fdb_kvdb_t db, kv_sec_info_t sector, size_t kv_size)
10711072

10721073
if ((empty_kv = alloc_kv(db, sector, kv_size)) == FAILED_ADDR) {
10731074
if (db->gc_request && !already_gc) {
1074-
FDB_INFO("Warning: Alloc an KV (size %" PRIu32 ") failed when new KV. Now will GC then retry.\n", (uint32_t)kv_size);
1075+
FDB_DEBUG("Alloc an KV (size %" PRIu32 ") failed when new KV. Now will GC then retry.\n", (uint32_t)kv_size);
10751076
gc_collect_by_free_size(db, kv_size);
10761077
already_gc = true;
10771078
goto __retry;
@@ -1093,10 +1094,12 @@ static uint32_t new_kv_ex(fdb_kvdb_t db, kv_sec_info_t sector, size_t key_len, s
10931094

10941095
static bool gc_check_cb(kv_sec_info_t sector, void *arg1, void *arg2)
10951096
{
1096-
size_t *empty_sec = arg1;
1097+
size_t *empty_sec_num = arg1;
1098+
uint32_t *empty_sec_addr = arg2;
10971099

10981100
if (sector->check_ok) {
1099-
*empty_sec = *empty_sec + 1;
1101+
*empty_sec_num = *empty_sec_num + 1;
1102+
*empty_sec_addr = sector->addr;
11001103
}
11011104

11021105
return false;
@@ -1108,6 +1111,7 @@ static bool do_gc(kv_sec_info_t sector, void *arg1, void *arg2)
11081111
struct fdb_kv kv;
11091112
struct gc_cb_args *gc = (struct gc_cb_args *)arg1;
11101113
fdb_kvdb_t db = gc->db;
1114+
uint32_t last_gc_sec_addr = 0;
11111115

11121116
if (sector->check_ok && (sector->status.dirty == FDB_SECTOR_DIRTY_TRUE || sector->status.dirty == FDB_SECTOR_DIRTY_GC)) {
11131117
uint8_t status_table[FDB_DIRTY_STATUS_TABLE_SIZE];
@@ -1122,15 +1126,22 @@ static bool do_gc(kv_sec_info_t sector, void *arg1, void *arg2)
11221126
if (move_kv(db, &kv) != FDB_NO_ERR) {
11231127
FDB_INFO("Error: Moved the KV (%.*s) for GC failed.\n", kv.name_len, kv.name);
11241128
}
1129+
} else {
1130+
FDB_DEBUG("KV (%.*s) is garbage NOT need move, collect it.\n", kv.name_len, kv.name);
11251131
}
11261132
} while ((kv.addr.start = get_next_kv_addr(db, sector, &kv)) != FAILED_ADDR);
11271133
format_sector(db, sector->addr, SECTOR_NOT_COMBINED);
1128-
gc->cur_free_size += db_sec_size(db) - SECTOR_HDR_DATA_SIZE;
1129-
FDB_DEBUG("Collect a sector @0x%08" PRIX32 "\n", sector->addr);
1134+
last_gc_sec_addr = gc->last_gc_sec_addr;
1135+
gc->last_gc_sec_addr = sector->addr;
11301136
/* update oldest_addr for next GC sector format */
11311137
db_oldest_addr(db) = get_next_sector_addr(db, sector, 0);
1132-
if (gc->cur_free_size >= gc->setting_free_size)
1133-
return true;
1138+
FDB_DEBUG("Collect a sector @0x%08" PRIX32 "\n", sector->addr);
1139+
/* the collect new space is in last GC sector */
1140+
struct kvdb_sec_info last_gc_sector;
1141+
if (read_sector_info(db, last_gc_sec_addr, &last_gc_sector, true) == FDB_NO_ERR) {
1142+
if (last_gc_sector.remain > gc->setting_free_size)
1143+
return true;
1144+
}
11341145
}
11351146

11361147
return false;
@@ -1139,15 +1150,17 @@ static bool do_gc(kv_sec_info_t sector, void *arg1, void *arg2)
11391150
static void gc_collect_by_free_size(fdb_kvdb_t db, size_t free_size)
11401151
{
11411152
struct kvdb_sec_info sector;
1142-
size_t empty_sec = 0;
1143-
struct gc_cb_args arg = { db, 0, free_size, 0 };
1153+
size_t empty_sec_num = 0;
1154+
/* an empty sector address */
1155+
uint32_t empty_sec_addr = 0;
11441156

11451157
/* GC check the empty sector number */
1146-
sector_iterator(db, &sector, FDB_SECTOR_STORE_EMPTY, &empty_sec, NULL, gc_check_cb, false);
1158+
sector_iterator(db, &sector, FDB_SECTOR_STORE_EMPTY, &empty_sec_num, &empty_sec_addr, gc_check_cb, false);
11471159

11481160
/* do GC collect */
1149-
FDB_DEBUG("The remain empty sector is %" PRIu32 ", GC threshold is %" PRIdLEAST16 ".\n", (uint32_t)empty_sec, FDB_GC_EMPTY_SEC_THRESHOLD);
1150-
if (empty_sec <= FDB_GC_EMPTY_SEC_THRESHOLD) {
1161+
FDB_DEBUG("The remain empty sector is %" PRIu32 ", GC threshold is %" PRIdLEAST16 ".\n", (uint32_t)empty_sec_num, FDB_GC_EMPTY_SEC_THRESHOLD);
1162+
if (empty_sec_num <= FDB_GC_EMPTY_SEC_THRESHOLD) {
1163+
struct gc_cb_args arg = { db, free_size, empty_sec_addr };
11511164
sector_iterator(db, &sector, FDB_SECTOR_STORE_UNUSED, &arg, NULL, do_gc, false);
11521165
}
11531166

@@ -1580,7 +1593,7 @@ static bool check_sec_hdr_cb(kv_sec_info_t sector, void *arg1, void *arg2)
15801593
if (db->parent.not_formatable) {
15811594
return true;
15821595
} else {
1583-
FDB_INFO("Sector header info is incorrect. Auto format this sector (0x%08" PRIX32 ").\n", sector->addr);
1596+
FDB_DEBUG("Sector header info is incorrect. Auto format this sector (0x%08" PRIX32 ").\n", sector->addr);
15841597
format_sector(db, sector->addr, SECTOR_NOT_COMBINED);
15851598
}
15861599
}

0 commit comments

Comments
 (0)