Skip to content

Commit 44ff312

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 e173175 commit 44ff312

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ 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+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
69+
6470
/* some useful macros */
6571
#define ZMS_NAME_HASH_ID(x) ((x & ZMS_HASH_TOTAL_MASK) | BIT(31))
6672
#define ZMS_UPDATE_COLLISION_NUM(x, y) \
@@ -71,6 +77,14 @@ struct settings_zms {
7177
struct settings_store cf_store;
7278
struct zms_fs cf_zms;
7379
const struct device *flash_dev;
80+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
81+
struct {
82+
uint32_t name_hash;
83+
uint8_t flags;
84+
} cache[CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE];
85+
86+
uint32_t cache_next;
87+
#endif
7488
uint32_t last_hash_id;
7589
uint32_t second_to_last_hash_id;
7690
uint8_t hash_collision_num;

subsys/settings/src/settings_zms.c

Lines changed: 104 additions & 3 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 cf->cache[cache_index].flags | BIT(0);
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 |= BIT(1);
214+
}
215+
/* set the delete BIT(1) indicating that the entry is deleted. */
216+
cache_flags |= BIT(2);
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;
@@ -199,6 +272,15 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
199272
break;
200273
}
201274

275+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
276+
uint8_t cache_flags = 0;
277+
278+
if (ZMS_COLLISION_NUM(ll_hash_id) > 0) {
279+
cache_flags |= BIT(1);
280+
}
281+
settings_zms_cache_add(cf, ll_hash_id & ZMS_HASH_MASK, cache_flags);
282+
#endif
283+
202284
/* update next ll_hash_id */
203285
ret = zms_read(&cf->cf_zms, ll_hash_id, &settings_element,
204286
sizeof(struct settings_hash_linked_list));
@@ -221,7 +303,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
221303
uint32_t collision_num = 0;
222304
bool delete;
223305
bool write_name;
224-
bool hash_collision;
225306
int rc = 0;
226307
int first_available_hash_index = -1;
227308

@@ -236,9 +317,22 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
236317
/* MSB is always 1 */
237318
name_hash |= BIT(31);
238319

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

243337
for (int i = 0; i <= cf->hash_collision_num; i++) {
244338
rc = zms_read(&cf->cf_zms, name_hash + i * LSB_GET(ZMS_COLLISIONS_MASK), &rdname,
@@ -295,7 +389,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
295389
/* hash doesn't exist, do not write anything here */
296390
return 0;
297391
}
298-
299392
rc = settings_zms_delete(cf, name_hash);
300393
return rc;
301394
}
@@ -341,6 +434,14 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
341434
cf->second_to_last_hash_id = cf->last_hash_id;
342435
cf->last_hash_id = name_hash | 1;
343436
}
437+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
438+
/* Add the flags of the written settings entry in cache */
439+
cache_flags = 0;
440+
if (ZMS_COLLISION_NUM(name_hash) > 0) {
441+
cache_flags |= BIT(1);
442+
}
443+
settings_zms_cache_add(cf, name_hash & ZMS_HASH_MASK, cache_flags);
444+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
344445

345446
return 0;
346447
}

0 commit comments

Comments
 (0)