[PATCH 16/40] util: macmap: Convert to use GSList for storing macs instead of string lists

Peter Krempa pkrempa at redhat.com
Sat Feb 6 08:32:38 UTC 2021


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 at 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




More information about the libvir-list mailing list