Skip to content

Commit a5d1d5c

Browse files
committed
[nrf fromlist] 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. Upstream PR #: 87792 Signed-off-by: Riadh Ghaddab <[email protected]> (cherry picked from commit 5e77c7f8f60d40b5a68626b3346b8b6f0440d6de)
1 parent ae4315d commit a5d1d5c

File tree

3 files changed

+117
-5
lines changed

3 files changed

+117
-5
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: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,43 @@ static int settings_zms_unlink_ll_node(struct settings_zms *cf, uint32_t name_ha
120120
return rc;
121121
}
122122

123+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
124+
static void settings_zms_cache_add(struct settings_zms *cf, uint32_t name_hash, uint8_t flags)
125+
{
126+
cf->cache[cf->cache_next].name_hash = name_hash;
127+
cf->cache[cf->cache_next++].flags = flags;
128+
129+
cf->cache_next %= CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE;
130+
}
131+
132+
static uint8_t settings_zms_cache_match(struct settings_zms *cf, uint32_t name_hash)
133+
{
134+
int cache_index;
135+
136+
if (!cf->cache_next) {
137+
cache_index = CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE - 1;
138+
} else {
139+
cache_index = cf->cache_next - 1;
140+
}
141+
142+
for (int i = 0; i < CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE; i++) {
143+
/* we check cache from recent values to old values */
144+
if (cf->cache[cache_index].name_hash != name_hash) {
145+
cache_index--;
146+
if (cache_index < 0) {
147+
cache_index = CONFIG_SETTINGS_ZMS_NAME_CACHE_SIZE - 1;
148+
}
149+
continue;
150+
}
151+
152+
/* set the BIT(0) to indicate that the name_hash exist in cache */
153+
return ZMS_CACHE_FLAG_SET_EXIST(cf->cache[cache_index].flags);
154+
}
155+
156+
return 0;
157+
}
158+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
159+
123160
static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
124161
{
125162
int rc = 0;
@@ -131,7 +168,6 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
131168
if (rc < 0) {
132169
return rc;
133170
}
134-
135171
rc = settings_zms_unlink_ll_node(cf, name_hash);
136172
if (rc < 0) {
137173
return rc;
@@ -143,6 +179,17 @@ static int settings_zms_delete(struct settings_zms *cf, uint32_t name_hash)
143179
return rc;
144180
}
145181

182+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
183+
/* Update the flag of the Settings entry in cache. */
184+
uint8_t cache_flags = 0;
185+
186+
if (ZMS_COLLISION_NUM(name_hash) > 0) {
187+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
188+
}
189+
/* set the delete BIT(2) indicating that the entry is deleted. */
190+
cache_flags = ZMS_CACHE_FLAG_SET_DELETED(cache_flags);
191+
settings_zms_cache_add(cf, name_hash & ZMS_HASH_MASK, cache_flags);
192+
#endif
146193
return rc;
147194
}
148195

@@ -194,6 +241,16 @@ static int settings_zms_load(struct settings_store *cs, const struct settings_lo
194241
read_fn_arg.fs = &cf->cf_zms;
195242
read_fn_arg.id = ZMS_NAME_ID_FROM_LL_NODE(ll_hash_id) + ZMS_DATA_ID_OFFSET;
196243

244+
#if CONFIG_SETTINGS_ZMS_NAME_CACHE
245+
/* Add the linked list node to cache */
246+
uint8_t cache_flags = 0;
247+
248+
if (ZMS_COLLISION_NUM(ll_hash_id) > 0) {
249+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
250+
}
251+
settings_zms_cache_add(cf, ll_hash_id & ZMS_HASH_MASK, cache_flags);
252+
#endif
253+
197254
ret = settings_call_set_handler(name, rc2, settings_zms_read_fn, &read_fn_arg,
198255
(void *)arg);
199256
if (ret) {
@@ -222,7 +279,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
222279
uint32_t collision_num = 0;
223280
bool delete;
224281
bool write_name;
225-
bool hash_collision;
226282
int rc = 0;
227283
int first_available_hash_index = -1;
228284

@@ -237,9 +293,22 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
237293
/* MSB is always 1 */
238294
name_hash |= BIT(31);
239295

240-
/* Let's find out if there are hash collisions in the storage */
296+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
297+
uint8_t cache_flags = 0;
298+
299+
cache_flags = settings_zms_cache_match(cf, name_hash & ZMS_HASH_MASK);
300+
if (ZMS_CACHE_EXIST(cache_flags) && !ZMS_CACHE_HAS_COLLISION(cache_flags)) {
301+
if (ZMS_CACHE_IS_DELETED(cache_flags)) {
302+
write_name = true;
303+
} else {
304+
write_name = false;
305+
}
306+
goto no_hash_collision;
307+
}
308+
#endif
309+
310+
/* Let's find out if there is no hash collisions in the storage */
241311
write_name = true;
242-
hash_collision = true;
243312

244313
for (int i = 0; i <= cf->hash_collision_num; i++) {
245314
rc = zms_read(&cf->cf_zms, name_hash + i * LSB_GET(ZMS_COLLISIONS_MASK), &rdname,
@@ -296,7 +365,6 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
296365
/* hash doesn't exist, do not write anything here */
297366
return 0;
298367
}
299-
300368
rc = settings_zms_delete(cf, name_hash);
301369
return rc;
302370
}
@@ -342,6 +410,14 @@ static int settings_zms_save(struct settings_store *cs, const char *name, const
342410
cf->second_to_last_hash_id = cf->last_hash_id;
343411
cf->last_hash_id = name_hash | 1;
344412
}
413+
#ifdef CONFIG_SETTINGS_ZMS_NAME_CACHE
414+
/* Add the flags of the written settings entry in cache */
415+
cache_flags = 0;
416+
if (ZMS_COLLISION_NUM(name_hash) > 0) {
417+
cache_flags = ZMS_CACHE_FLAG_SET_COLLISION(cache_flags);
418+
}
419+
settings_zms_cache_add(cf, name_hash & ZMS_HASH_MASK, cache_flags);
420+
#endif /* CONFIG_SETTINGS_ZMS_NAME_CACHE */
345421

346422
return 0;
347423
}

0 commit comments

Comments
 (0)