Skip to content

Commit 2ce391b

Browse files
committed
settings: zms: add a cache to accelerate write/delete
adding a lookup cache improves write and delete operation as it doesn't look for the name in the storage if no hash collision exists or if the entry is deleted. Signed-off-by: Riadh Ghaddab <[email protected]>
1 parent 23d5461 commit 2ce391b

File tree

3 files changed

+142
-4
lines changed

3 files changed

+142
-4
lines changed

subsys/settings/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ config SETTINGS_ZMS
4747
help
4848
Use ZMS as settings storage backend.
4949

50+
if SETTINGS_ZMS
51+
52+
config SETTINGS_ZMS_NAME_CACHE
53+
bool "ZMS name lookup cache"
54+
select SYS_HASH_FUNC32
55+
help
56+
Enable ZMS lookup cache, used to reduce the Settings name
57+
lookup time by checking if its hash had a collision.
58+
59+
config SETTINGS_ZMS_NAME_CACHE_SIZE
60+
int "ZMS name lookup cache size"
61+
default 128
62+
range 1 $(UINT32_MAX)
63+
depends on SETTINGS_ZMS_NAME_CACHE
64+
help
65+
Number of entries in Settings ZMS name cache.
66+
67+
endif # SETTINGS_ZMS
68+
5069
config SETTINGS_FCB
5170
bool "FCB"
5271
depends on FCB

subsys/settings/include/settings/settings_zms.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ extern "C" {
6161
#define ZMS_HASH_TOTAL_MASK GENMASK(29, 1)
6262
#define ZMS_MAX_COLLISIONS (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1)
6363

64+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
65+
#define ZMS_CACHE_EXIST(x) (x & BIT(0))
66+
#define ZMS_CACHE_HAS_COLLISION(x) (x & BIT(1))
67+
#define ZMS_CACHE_IS_DELETED(x) (x & BIT(2))
68+
#define ZMS_CACHE_FLAG_SET_EXIST(x) (x | BIT(0))
69+
#define ZMS_CACHE_FLAG_SET_COLLISION(x) (x | BIT(1))
70+
#define ZMS_CACHE_FLAG_SET_DELETED(x) (x | BIT(2))
71+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
72+
6473
/* some useful macros */
6574
#define ZMS_NAME_ID_FROM_LL_NODE(x) (x & ~BIT(0))
6675
#define ZMS_UPDATE_COLLISION_NUM(x, y) \
@@ -71,6 +80,14 @@ struct settings_zms {
7180
struct settings_store cf_store;
7281
struct zms_fs cf_zms;
7382
const struct device *flash_dev;
83+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
84+
struct {
85+
uint32_t name_hash;
86+
uint8_t flags;
87+
} cache[CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE];
88+
89+
uint32_t cache_next;
90+
#endif
7491
uint32_t last_hash_id;
7592
uint32_t second_to_last_hash_id;
7693
uint8_t hash_collision_num;

subsys/settings/src/settings_zms.c

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,79 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
146146
return rc;
147147
}
148148

149+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
150+
static void settings_zms_cache_add(struct settings_zms *cf, uint32_t name_hash, uint8_t flags)
151+
{
152+
cf->cache[cf->cache_next].name_hash = name_hash;
153+
cf->cache[cf->cache_next++].flags = flags;
154+
155+
cf->cache_next %= CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE;
156+
}
157+
158+
static uint8_t settings_zms_cache_match(struct settings_zms *cf, uint32_t name_hash)
159+
{
160+
int cache_index;
161+
162+
if (!cf->cache_next) {
163+
cache_index = CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE - 1;
164+
} else {
165+
cache_index = cf->cache_next - 1;
166+
}
167+
168+
for (int i = 0; i < CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE; i++) {
169+
/* we check cache from recent values to old values */
170+
if (cf->cache[cache_index].name_hash != name_hash) {
171+
cache_index--;
172+
if (cache_index < 0) {
173+
cache_index = CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE - 1;
174+
}
175+
continue;
176+
}
177+
178+
/* set the BIT(0) to indicate that the name_hash exist in cache */
179+
return ZMS_CACHE_FLAG_SET_EXIST(cf->cache[cache_index].flags);
180+
}
181+
182+
return 0;
183+
}
184+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
185+
186+
static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
187+
{
188+
int rc = 0;
189+
190+
rc = zms_delete(&cf->cf_zms, name_hash);
191+
if (rc >= 0) {
192+
rc = zms_delete(&cf->cf_zms, name_hash + ZMS_DATA_ID_OFFSET);
193+
}
194+
if (rc < 0) {
195+
return rc;
196+
}
197+
rc = settings_zms_unlink_ll_node(cf, name_hash);
198+
if (rc < 0) {
199+
return rc;
200+
}
201+
202+
/* Now delete the current linked list element */
203+
rc = zms_delete(&cf->cf_zms, name_hash | 1);
204+
if (rc < 0) {
205+
return rc;
206+
}
207+
208+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
209+
/* Update the flag of the Settings entry in cache. */
210+
uint8_t cache_flags = 0;
211+
212+
if (ZMS_COLLISION_NUM(name_hash) > 0) {
213+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
214+
}
215+
/* set the delete BIT(2) indicating that the entry is deleted. */
216+
cache_flags = ZMS_CACHE_FLAG_SET_DELETED(cache_flags);
217+
settings_zms_cache_add(cf, name_hash & ZMS_HASH_MASK, cache_flags);
218+
#endif
219+
return rc;
220+
}
221+
149222
static int settings_zms_load(struct settings_store *cs, const struct settings_load_arg *arg)
150223
{
151224
int ret = 0;
@@ -194,6 +267,16 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
194267
read_fn_arg.fs = &cf->cf_zms;
195268
read_fn_arg.id = ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id) + ZMS_DATA_ID_OFFSET;
196269

270+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
271+
/* Add the linked list node to cache */
272+
uint8_t cache_flags = 0;
273+
274+
if (ZMS_COLLISION_NUM(ll_hash_id) > 0) {
275+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
276+
}
277+
settings_zms_cache_add(cf, ll_hash_id & ZMS_HASH_MASK, cache_flags);
278+
#endif
279+
197280
ret = settings_call_set_handler(name, rc2, settings_zms_read_fn, &read_fn_arg,
198281
(void *)arg);
199282
if (ret) {
@@ -222,7 +305,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
222305
uint32_t collision_num = 0;
223306
bool delete;
224307
bool write_name;
225-
bool hash_collision;
226308
int rc = 0;
227309
int first_available_hash_index = -1;
228310

@@ -237,9 +319,22 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
237319
/* MSB is always 1 */
238320
name_hash |= BIT(31);
239321

240-
/* Let's find out if there are hash collisions in the storage */
322+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
323+
uint8_t cache_flags = 0;
324+
325+
cache_flags = settings_zms_cache_match(cf, name_hash & ZMS_HASH_MASK);
326+
if (ZMS_CACHE_EXIST(cache_flags) && !ZMS_CACHE_HAS_COLLISION(cache_flags)) {
327+
if (ZMS_CACHE_IS_DELETED(cache_flags)) {
328+
write_name = true;
329+
} else {
330+
write_name = false;
331+
}
332+
goto no_hash_collision;
333+
}
334+
#endif
335+
336+
/* Let's find out if there is no hash collisions in the storage */
241337
write_name = true;
242-
hash_collision = true;
243338

244339
for (int i = 0; i <= cf->hash_collision_num; i++) {
245340
rc = zms_read(&cf->cf_zms, name_hash + i * LSB_GET(ZMS_COLLISIONS_MASK), &rdname,
@@ -296,7 +391,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
296391
/* hash doesn't exist, do not write anything here */
297392
return 0;
298393
}
299-
300394
rc = settings_zms_delete(cf, name_hash);
301395
return rc;
302396
}
@@ -342,6 +436,14 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
342436
cf->second_to_last_hash_id = cf->last_hash_id;
343437
cf->last_hash_id = name_hash | 1;
344438
}
439+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
440+
/* Add the flags of the written settings entry in cache */
441+
cache_flags = 0;
442+
if (ZMS_COLLISION_NUM(name_hash) > 0) {
443+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
444+
}
445+
settings_zms_cache_add(cf, name_hash & ZMS_HASH_MASK, cache_flags);
446+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
345447

346448
return 0;
347449
}

0 commit comments

Comments
 (0)