]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: macmap: Convert to use GSList for storing macs instead of string lists
authorPeter Krempa <pkrempa@redhat.com>
Fri, 5 Feb 2021 13:25:16 +0000 (14:25 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 11 Feb 2021 16:05:33 +0000 (17:05 +0100)
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@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/util/virmacmap.c
src/util/virmacmap.h
tests/virmacmaptest.c

index ec0a67b4331bccfdc07ff35d748a7561f3504061..0d458d7b7b0e691ae2d7432a8b5300806941cac7 100644 (file)
@@ -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);
index 4652295033af72da30e448a8ce2e27383a6b9752..96e32256e3e33a4c5fe85e35a561154570c9fdd3 100644 (file)
@@ -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);
index 8fd9916b95b700c9a07d463676125bc665fb8eda..77fa2b3e9818f1a6dfd92bfd5726e90fb5abe355 100644 (file)
@@ -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;
     }