Since adding and removing is the main use case for the macmap module,
convert the code to a more efficient data structure.
The refactor also optimizes the loading from file where previously we'd
do a hash lookup + list lenght calculation for every entry.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/util/virmacmap.c | 118 +++++++++++++++++++++++-------------------
src/util/virmacmap.h | 6 ++-
tests/virmacmaptest.c | 21 ++++----
3 files changed, 81 insertions(+), 64 deletions(-)
diff --git a/src/util/virmacmap.c b/src/util/virmacmap.c
index ec0a67b433..0d458d7b7b 100644
--- a/src/util/virmacmap.c
+++ b/src/util/virmacmap.c
@@ -50,21 +50,18 @@ struct virMacMap {
static virClassPtr virMacMapClass;
-static int
-virMacMapHashFree(void *payload,
- const char *name G_GNUC_UNUSED,
- void *opaque G_GNUC_UNUSED)
-{
- g_strfreev(payload);
- return 0;
-}
-
-
static void
virMacMapDispose(void *obj)
{
virMacMapPtr mgr = obj;
- virHashForEach(mgr->macs, virMacMapHashFree, NULL);
+ GHashTableIter htitr;
+ void *value;
+
+ g_hash_table_iter_init(&htitr, mgr->macs);
+
+ while (g_hash_table_iter_next(&htitr, NULL, &value))
+ g_slist_free_full(value, g_free);
+
virHashFree(mgr->macs);
}
@@ -80,48 +77,57 @@ static int virMacMapOnceInit(void)
VIR_ONCE_GLOBAL_INIT(virMacMap);
-static int
+static void
virMacMapAddLocked(virMacMapPtr mgr,
const char *domain,
const char *mac)
{
- char **macsList = NULL;
+ GSList *orig_list;
+ GSList *list;
+ GSList *next;
- if ((macsList = virHashLookup(mgr->macs, domain)) &&
- virStringListHasString((const char**) macsList, mac)) {
- return 0;
+ list = orig_list = g_hash_table_lookup(mgr->macs, domain);
+
+ for (next = list; next; next = next->next) {
+ if (STREQ((const char *) next->data, mac))
+ return;
}
- if (virStringListAdd(&macsList, mac) < 0 ||
- virHashUpdateEntry(mgr->macs, domain, macsList) < 0)
- return -1;
+ list = g_slist_append(list, g_strdup(mac));
- return 0;
+ if (list != orig_list)
+ g_hash_table_insert(mgr->macs, g_strdup(domain), list);
}
-static int
+static void
virMacMapRemoveLocked(virMacMapPtr mgr,
const char *domain,
const char *mac)
{
- char **macsList = NULL;
- char **newMacsList = NULL;
+ GSList *orig_list;
+ GSList *list;
+ GSList *next;
- if (!(macsList = virHashLookup(mgr->macs, domain)))
- return 0;
+ list = orig_list = g_hash_table_lookup(mgr->macs, domain);
- newMacsList = macsList;
- virStringListRemove(&newMacsList, mac);
- if (!newMacsList) {
- virHashSteal(mgr->macs, domain);
- } else {
- if (macsList != newMacsList &&
- virHashUpdateEntry(mgr->macs, domain, newMacsList) < 0)
- return -1;
+ if (!orig_list)
+ return;
+
+ for (next = list; next; next = next->next) {
+ if (STREQ((const char *) next->data, mac)) {
+ list = g_slist_remove_link(list, next);
+ g_slist_free_full(next, g_free);
+ break;
+ }
}
- return 0;
+ if (list != orig_list) {
+ if (list)
+ g_hash_table_insert(mgr->macs, g_strdup(domain), list);
+ else
+ g_hash_table_remove(mgr->macs, domain);
+ }
}
@@ -162,6 +168,7 @@ virMacMapLoadFile(virMacMapPtr mgr,
virJSONValuePtr macs;
const char *domain;
size_t j;
+ GSList *vals = NULL;
if (!(domain = virJSONValueObjectGetString(tmp, "domain"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -175,13 +182,21 @@ virMacMapLoadFile(virMacMapPtr mgr,
return -1;
}
+ if (g_hash_table_contains(mgr->macs, domain)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("duplicate domain '%s'"), domain);
+ return -1;
+
+ }
+
for (j = 0; j < virJSONValueArraySize(macs); j++) {
virJSONValuePtr macJSON = virJSONValueArrayGet(macs, j);
- const char *mac = virJSONValueGetString(macJSON);
- if (virMacMapAddLocked(mgr, domain, mac) < 0)
- return -1;
+ vals = g_slist_prepend(vals, g_strdup(virJSONValueGetString(macJSON)));
}
+
+ vals = g_slist_reverse(vals);
+ g_hash_table_insert(mgr->macs, g_strdup(domain), vals);
}
return 0;
@@ -195,11 +210,11 @@ virMACMapHashDumper(void *payload,
{
g_autoptr(virJSONValue) obj = virJSONValueNewObject();
g_autoptr(virJSONValue) arr = virJSONValueNewArray();
- const char **macs = payload;
- size_t i;
+ GSList *macs = payload;
+ GSList *next;
- for (i = 0; macs[i]; i++) {
- virJSONValuePtr m = virJSONValueNewString(macs[i]);
+ for (next = macs; next; next = next->next) {
+ virJSONValuePtr m = virJSONValueNewString((const char *) next->data);
if (!m ||
virJSONValueArrayAppend(arr, m) < 0) {
@@ -279,8 +294,8 @@ virMacMapNew(const char *file)
return NULL;
virObjectLock(mgr);
- if (!(mgr->macs = virHashNew(NULL)))
- goto error;
+
+ mgr->macs = virHashNew(NULL);
if (file &&
virMacMapLoadFile(mgr, file) < 0)
@@ -301,12 +316,10 @@ virMacMapAdd(virMacMapPtr mgr,
const char *domain,
const char *mac)
{
- int ret;
-
virObjectLock(mgr);
- ret = virMacMapAddLocked(mgr, domain, mac);
+ virMacMapAddLocked(mgr, domain, mac);
virObjectUnlock(mgr);
- return ret;
+ return 0;
}
@@ -315,20 +328,19 @@ virMacMapRemove(virMacMapPtr mgr,
const char *domain,
const char *mac)
{
- int ret;
-
virObjectLock(mgr);
- ret = virMacMapRemoveLocked(mgr, domain, mac);
+ virMacMapRemoveLocked(mgr, domain, mac);
virObjectUnlock(mgr);
- return ret;
+ return 0;
}
-const char *const *
+/* note that the returned pointer may be invalidated by other APIs in this module */
+GSList *
virMacMapLookup(virMacMapPtr mgr,
const char *domain)
{
- const char *const *ret;
+ GSList *ret;
virObjectLock(mgr);
ret = virHashLookup(mgr->macs, domain);
diff --git a/src/util/virmacmap.h b/src/util/virmacmap.h
index 4652295033..96e32256e3 100644
--- a/src/util/virmacmap.h
+++ b/src/util/virmacmap.h
@@ -20,6 +20,8 @@
#pragma once
+#include "internal.h"
+
typedef struct virMacMap virMacMap;
typedef virMacMap *virMacMapPtr;
@@ -37,8 +39,8 @@ int virMacMapRemove(virMacMapPtr mgr,
const char *domain,
const char *mac);
-const char *const *virMacMapLookup(virMacMapPtr mgr,
- const char *domain);
+GSList *virMacMapLookup(virMacMapPtr mgr,
+ const char *domain);
int virMacMapWriteFile(virMacMapPtr mgr,
const char *filename);
diff --git a/tests/virmacmaptest.c b/tests/virmacmaptest.c
index 8fd9916b95..77fa2b3e98 100644
--- a/tests/virmacmaptest.c
+++ b/tests/virmacmaptest.c
@@ -36,7 +36,8 @@ testMACLookup(const void *opaque)
{
const struct testData *data = opaque;
virMacMapPtr mgr = NULL;
- const char * const * macs;
+ GSList *macs;
+ GSList *next;
size_t i, j;
char *file = NULL;
int ret = -1;
@@ -48,26 +49,27 @@ testMACLookup(const void *opaque)
macs = virMacMapLookup(mgr, data->domain);
- for (i = 0; macs && macs[i]; i++) {
+ for (next = macs; next; next = next->next) {
for (j = 0; data->macs && data->macs[j]; j++) {
- if (STREQ(macs[i], data->macs[j]))
+ if (STREQ((const char *) next->data, data->macs[j]))
break;
}
if (!data->macs || !data->macs[j]) {
fprintf(stderr,
- "Unexpected %s in the returned list of MACs\n", macs[i]);
+ "Unexpected %s in the returned list of MACs\n",
+ (const char *) next->data);
goto cleanup;
}
}
for (i = 0; data->macs && data->macs[i]; i++) {
- for (j = 0; macs && macs[j]; j++) {
- if (STREQ(data->macs[i], macs[j]))
+ for (next = macs; next; next = next->next) {
+ if (STREQ(data->macs[i], (const char *) next->data))
break;
}
- if (!macs || !macs[j]) {
+ if (!next) {
fprintf(stderr,
"Expected %s in the returned list of MACs\n",
data->macs[i]);
goto cleanup;
@@ -87,7 +89,7 @@ testMACRemove(const void *opaque)
{
const struct testData *data = opaque;
virMacMapPtr mgr = NULL;
- const char * const * macs;
+ GSList *macs;
size_t i;
char *file = NULL;
int ret = -1;
@@ -107,7 +109,8 @@ testMACRemove(const void *opaque)
if ((macs = virMacMapLookup(mgr, data->domain))) {
fprintf(stderr,
- "Not removed all MACs for domain %s: %s\n", data->domain,
macs[0]);
+ "Not removed all MACs for domain %s: %s\n",
+ data->domain, (const char *) macs->data);
goto cleanup;
}
--
2.29.2