summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-06-16 09:50:39 +0200
committerThomas Haller <thaller@redhat.com>2021-06-21 17:23:53 +0200
commit2f9ab1d5280bb21b21d358a6595e96617a57d777 (patch)
treee8fa6737df05ab9024cb7d919b81b975bb891415
parentb929caa95cfc6f2bcf0dfd22a0743abdbcd9838c (diff)
config: add lookup index for _match_section_infos_lookup()
Previously, we would call g_key_file_get_string(), which requires two hash lookups (one for the group and one for the key). We can do better. Especially since NMConfigData is immutable, it's simple to build a lookup index of the values we have and then do binary search. Note that we call nm_config_data_get_connection_default() and similar API *a lot*, so this is measurable.
-rw-r--r--src/core/nm-config-data.c109
1 files changed, 96 insertions, 13 deletions
diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c
index fa1cc49a78..f6667e926d 100644
--- a/src/core/nm-config-data.c
+++ b/src/core/nm-config-data.c
@@ -26,6 +26,8 @@ typedef struct {
gboolean has;
GSList * spec;
} match_device;
+ gsize lookup_len;
+ const NMUtilsNamedValue *lookup_idx;
} MatchSectionInfo;
struct _NMGlobalDnsDomain {
@@ -116,6 +118,11 @@ G_DEFINE_TYPE(NMConfigData, nm_config_data, G_TYPE_OBJECT)
/*****************************************************************************/
+static const char *
+_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property);
+
+/*****************************************************************************/
+
const char *
nm_config_data_get_config_main_file(const NMConfigData *self)
{
@@ -1395,13 +1402,13 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
const char *match_dhcp_plugin;
if (!match_section_infos)
- return NULL;
+ goto out;
match_dhcp_plugin = nm_dhcp_manager_get_config(nm_dhcp_manager_get());
for (; match_section_infos->group_name; match_section_infos++) {
- char * value = NULL;
- gboolean match;
+ const char *value;
+ gboolean match;
/* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader
* does.
@@ -1410,7 +1417,7 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
* string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would
* expose both functions, and we would return here keyfile_to_string(keyfile).
* The caller then could convert the string to the proper value via string_to_value(value). */
- value = g_key_file_get_string(keyfile, match_section_infos->group_name, property, NULL);
+ value = _match_section_info_get_str(match_section_infos, keyfile, property);
if (!value && !match_section_infos->stop_match)
continue;
@@ -1429,11 +1436,13 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
match = TRUE;
if (match) {
- *out_value = value;
+ *out_value = g_strdup(value);
return match_section_infos;
}
- g_free(value);
}
+
+out:
+ *out_value = NULL;
return NULL;
}
@@ -1580,9 +1589,35 @@ nm_config_data_get_connection_default_int64(const NMConfigData *self,
return _nm_utils_ascii_str_to_int64(value, 10, min, max, fallback);
}
+static const char *
+_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property)
+{
+ gssize idx;
+ const char *value;
+
+ idx = nm_utils_named_value_list_find(m->lookup_idx, m->lookup_len, property, TRUE);
+ value = idx >= 0 ? m->lookup_idx[idx].value_str : NULL;
+
+#if NM_MORE_ASSERTS > 10
+ {
+ gs_free char *value2 = g_key_file_get_string(keyfile, m->group_name, property, NULL);
+
+ nm_assert(nm_streq0(value2, value));
+ }
+#endif
+
+ return value;
+}
+
static void
-_get_connection_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
+_match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
{
+ char ** keys = NULL;
+ gsize n_keys;
+ gsize i;
+ gsize j;
+ NMUtilsNamedValue *vals;
+
/* pass ownership of @group on... */
connection_info->group_name = group;
@@ -1593,18 +1628,66 @@ _get_connection_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile,
&connection_info->match_device.has);
connection_info->stop_match =
nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE);
+
+ keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL);
+ nm_utils_strv_sort(keys, n_keys);
+
+ vals = g_new(NMUtilsNamedValue, n_keys);
+
+ for (i = 0, j = 0; i < n_keys; i++) {
+ gs_free char *key = g_steal_pointer(&keys[i]);
+ char * value;
+
+ if (NM_IN_STRSET(key, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE))
+ continue;
+
+ if (j > 0 && nm_streq(vals[j - 1].name, key))
+ continue;
+
+ value = g_key_file_get_string(keyfile, group, key, NULL);
+ if (!value)
+ continue;
+
+ vals[j++] = (NMUtilsNamedValue){
+ .name = g_steal_pointer(&key),
+ .value_str = value,
+ };
+ }
+
+ g_free(keys);
+
+ if (n_keys != j) {
+ gs_free NMUtilsNamedValue *vals2 = vals;
+
+ /* since this buffer will be kept around for a long time,
+ * get rid of the excess allocation. */
+ vals = nm_memdup(vals2, sizeof(NMUtilsNamedValue) * j);
+ n_keys = j;
+ }
+
+ if (n_keys == 0)
+ nm_clear_g_free(&vals);
+
+ connection_info->lookup_idx = vals;
+ connection_info->lookup_len = n_keys;
}
static void
_match_section_infos_free(MatchSectionInfo *match_section_infos)
{
- guint i;
+ MatchSectionInfo *m;
+ gsize i;
if (!match_section_infos)
return;
- for (i = 0; match_section_infos[i].group_name; i++) {
- g_free(match_section_infos[i].group_name);
- g_slist_free_full(match_section_infos[i].match_device.spec, g_free);
+ for (m = match_section_infos; m->group_name; m++) {
+ g_free(m->group_name);
+ g_slist_free_full(m->match_device.spec, g_free);
+ for (i = 0; i < m->lookup_len; i++) {
+ g_free(m->lookup_idx[i].name_mutable);
+ g_free(m->lookup_idx[i].value_str_mutable);
+ }
+ g_free((gpointer) m->lookup_idx);
}
g_free(match_section_infos);
}
@@ -1649,11 +1732,11 @@ _match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
for (i = 0; i < ngroups; i++) {
/* pass ownership of @group on... */
- _get_connection_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
+ _match_section_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
}
if (connection_tag) {
/* pass ownership of @connection_tag on... */
- _get_connection_info_init(&match_section_infos[i], keyfile, connection_tag);
+ _match_section_info_init(&match_section_infos[i], keyfile, connection_tag);
}
g_free(groups);