From afb1fe36b835633228a6bdd0bfd09dafdc9afa65 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 28 Jun 2024 16:16:50 +0200 Subject: [PATCH 1/2] introduce hashmap_ensure_replace() Similar to hashmap_ensure_put(), but replace existing items in the map, as hashmap_replace(). --- src/basic/hashmap.c | 20 ++++++++++++++++++++ src/basic/hashmap.h | 5 +++++ src/test/test-hashmap-plain.c | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index a9fd7620295..951f63ae6da 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -874,6 +874,26 @@ int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ return ordered_hashmap_put(*h, key, value); } +int _ordered_hashmap_ensure_replace(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) { + int r; + + r = _ordered_hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS); + if (r < 0) + return r; + + return ordered_hashmap_replace(*h, key, value); +} + +int _hashmap_ensure_replace(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) { + int r; + + r = _hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS); + if (r < 0) + return r; + + return hashmap_replace(*h, key, value); +} + static void hashmap_free_no_clear(HashmapBase *h) { assert(!h->has_indirect); assert(h->n_direct_entries == 0); diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 49d9d118cc3..01a4fb32043 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -130,14 +130,19 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); int _hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +int _hashmap_ensure_replace(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); #define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define hashmap_ensure_put(s, ops, key, value) _hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) +#define hashmap_ensure_replace(s, ops, key, value) _hashmap_ensure_replace(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); #define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) +int _ordered_hashmap_ensure_replace(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); +#define ordered_hashmap_ensure_replace(s, ops, key, value) _ordered_hashmap_ensure_replace(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) + IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h); static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) { return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index f2d2d4f75da..cb45c150879 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -49,6 +49,30 @@ TEST(hashmap_replace) { ASSERT_STREQ(r, "val5"); } +TEST(hashmap_ensure_replace) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + _cleanup_free_ char *val1 = NULL, *val2 = NULL; + + val1 = strdup("val1"); + ASSERT_NOT_NULL(val1); + val2 = strdup("val2"); + ASSERT_NOT_NULL(val2); + + ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, val1, val2)); + + ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 1", val1)); + ASSERT_STREQ(hashmap_get(m, "key 1"), "val1"); + + ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 2", val2)); + ASSERT_STREQ(hashmap_get(m, "key 2"), "val2"); + + ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 3", val1)); + ASSERT_STREQ(hashmap_get(m, "key 3"), "val1"); + + ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 3", val2)); + ASSERT_STREQ(hashmap_get(m, "key 3"), "val2"); +} + TEST(hashmap_copy) { _cleanup_hashmap_free_ Hashmap *m = NULL; _cleanup_hashmap_free_free_ Hashmap *copy = NULL; From e1226a9b488d5677b10f086cabf610131c66d5aa Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 28 Jun 2024 17:19:26 +0200 Subject: [PATCH 2/2] Use hashmap_ensure_replace() Use the new function `hashmap_ensure_replace()` where we're using `hashmap_ensure_allocated()` and `hashmap_ensure_replace()`. Signed-off-by: Matteo Croce --- src/core/unit.c | 7 +------ src/libsystemd/sd-hwdb/sd-hwdb.c | 6 +----- src/libsystemd/sd-netlink/netlink-socket.c | 8 +------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/core/unit.c b/src/core/unit.c index 0e931be4846..a4e96116fc2 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2805,13 +2805,8 @@ int unit_watch_pidref(Unit *u, const PidRef *pid, bool exclusive) { new_array[n] = u; new_array[n+1] = NULL; - /* Make sure the hashmap is allocated */ - r = hashmap_ensure_allocated(&u->manager->watch_pids_more, &pidref_hash_ops_free); - if (r < 0) - return r; - /* Add or replace the old array */ - r = hashmap_replace(u->manager->watch_pids_more, old_pid ?: pid, new_array); + r = hashmap_ensure_replace(&u->manager->watch_pids_more, &pidref_hash_ops_free, old_pid ?: pid, new_array); if (r < 0) return r; diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index f623d470648..11c5092bc97 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -166,11 +166,7 @@ static int hwdb_add_property(sd_hwdb *hwdb, const struct trie_value_entry_f *ent } } - r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_replace(hwdb->properties, key, (void *)entry); + r = ordered_hashmap_ensure_replace(&hwdb->properties, &string_hash_ops, key, (void *) entry); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 64cde89ecfa..d09dc31fa32 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -86,15 +86,9 @@ static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) { } static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) { - int r; - assert(nl); - r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); - if (r < 0) - return r; - - return hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref)); + return hashmap_ensure_replace(&nl->broadcast_group_refs, NULL, UINT_TO_PTR(group), UINT_TO_PTR(n_ref)); } static int broadcast_group_join(sd_netlink *nl, unsigned group) {