[libvirt] [PATCH 14/16] snapshot: Move snapshot list code into generic file

Eric Blake eblake at redhat.com
Wed Mar 20 05:41:03 UTC 2019


Finish the code motion of generic moment list handling. Well, mostly -
we need to convert to using virObject to get polymorphic cleanup
functions (so for now there are still a few lingering ties specific to
snapshots).  In this case, I kept virDomainSnapshotObjList as a
wrapper type around the new generic virDomainMomentObjList; the bulk
of the algorithms move, but the old functions remain and forward to
the generic helpers.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 src/conf/virconftypes.h             |   3 +
 src/conf/virdomainmomentobjlist.h   |  32 +++
 src/conf/virdomainsnapshotobjlist.h |   6 -
 src/conf/virdomainmomentobjlist.c   | 356 ++++++++++++++++++++++++++++
 src/conf/virdomainsnapshotobjlist.c | 266 +++------------------
 5 files changed, 422 insertions(+), 241 deletions(-)

diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index 574815cf04..6a8267c422 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -223,6 +223,9 @@ typedef virDomainMomentDef *virDomainMomentDefPtr;
 typedef struct _virDomainMomentObj virDomainMomentObj;
 typedef virDomainMomentObj *virDomainMomentObjPtr;

+typedef struct _virDomainMomentObjList virDomainMomentObjList;
+typedef virDomainMomentObjList *virDomainMomentObjListPtr;
+
 typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
 typedef virDomainNVRAMDef *virDomainNVRAMDefPtr;

diff --git a/src/conf/virdomainmomentobjlist.h b/src/conf/virdomainmomentobjlist.h
index dceb55fca2..4d765c552f 100644
--- a/src/conf/virdomainmomentobjlist.h
+++ b/src/conf/virdomainmomentobjlist.h
@@ -27,6 +27,10 @@
 # include "virconftypes.h"
 # include "virhash.h"

+/* Filter that returns true if a given moment matches the filter flags */
+typedef bool (*virDomainMomentObjListFilter)(virDomainMomentObjPtr obj,
+                                             unsigned int flags);
+
 /* Struct that allows tracing hierarchical relationships between
  * multiple virDomainMoment objects. The opaque type
  * virDomainMomentObjList then maintains both a hash of these structs
@@ -60,4 +64,32 @@ void virDomainMomentMoveChildren(virDomainMomentObjPtr from,
 void virDomainMomentSetParent(virDomainMomentObjPtr moment,
                               virDomainMomentObjPtr parent);

+virDomainMomentObjListPtr virDomainMomentObjListNew(virDomainMomentObjListFilter filter);
+void virDomainMomentObjListFree(virDomainMomentObjListPtr moments);
+
+virDomainMomentObjPtr virDomainMomentAssignDef(virDomainMomentObjListPtr moments,
+                                               virDomainMomentDefPtr def);
+
+int virDomainMomentObjListGetNames(virDomainMomentObjListPtr moments,
+                                   virDomainMomentObjPtr from,
+                                   char **const names,
+                                   int maxnames,
+                                   unsigned int flags);
+virDomainMomentObjPtr virDomainMomentFindByName(virDomainMomentObjListPtr moments,
+                                                const char *name);
+int virDomainMomentObjListSize(virDomainMomentObjListPtr moments);
+virDomainMomentObjPtr virDomainMomentGetCurrent(virDomainMomentObjListPtr moments);
+const char *virDomainMomentGetCurrentName(virDomainMomentObjListPtr moments);
+bool virDomainMomentIsCurrentName(virDomainMomentObjListPtr moments,
+                                  const char *name);
+void virDomainMomentSetCurrent(virDomainMomentObjListPtr moments,
+                               virDomainMomentObjPtr moment);
+bool virDomainMomentObjListRemove(virDomainMomentObjListPtr moments,
+                                  virDomainMomentObjPtr moment);
+void virDomainMomentObjListRemoveAll(virDomainMomentObjListPtr moments);
+int virDomainMomentForEach(virDomainMomentObjListPtr moments,
+                           virHashIterator iter,
+                           void *data);
+int virDomainMomentUpdateRelations(virDomainMomentObjListPtr moments);
+
 #endif /* LIBVIRT_VIRDOMAINMOMENTOBJLIST_H */
diff --git a/src/conf/virdomainsnapshotobjlist.h b/src/conf/virdomainsnapshotobjlist.h
index c36b498751..9daecacfdc 100644
--- a/src/conf/virdomainsnapshotobjlist.h
+++ b/src/conf/virdomainsnapshotobjlist.h
@@ -27,10 +27,6 @@
 # include "virdomainmomentobjlist.h"
 # include "virbuffer.h"

-/* Filter that returns true if a given moment matches the filter flags */
-typedef bool (*virDomainMomentObjListFilter)(virDomainMomentObjPtr obj,
-                                             unsigned int flags);
-
 virDomainSnapshotObjListPtr virDomainSnapshotObjListNew(void);
 void virDomainSnapshotObjListFree(virDomainSnapshotObjListPtr snapshots);

@@ -59,7 +55,6 @@ int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots,
                                 unsigned int flags);
 virDomainMomentObjPtr virDomainSnapshotFindByName(virDomainSnapshotObjListPtr snapshots,
                                                   const char *name);
-int virDomainSnapshotObjListSize(virDomainSnapshotObjListPtr snapshots);
 virDomainMomentObjPtr virDomainSnapshotGetCurrent(virDomainSnapshotObjListPtr snapshots);
 const char *virDomainSnapshotGetCurrentName(virDomainSnapshotObjListPtr snapshots);
 bool virDomainSnapshotIsCurrentName(virDomainSnapshotObjListPtr snapshots,
@@ -68,7 +63,6 @@ void virDomainSnapshotSetCurrent(virDomainSnapshotObjListPtr snapshots,
                                  virDomainMomentObjPtr snapshot);
 bool virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
                                     virDomainMomentObjPtr snapshot);
-void virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjListPtr snapshots);
 int virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots,
                              virHashIterator iter,
                              void *data);
diff --git a/src/conf/virdomainmomentobjlist.c b/src/conf/virdomainmomentobjlist.c
index 766d7fe2e4..f987329a6b 100644
--- a/src/conf/virdomainmomentobjlist.c
+++ b/src/conf/virdomainmomentobjlist.c
@@ -29,10 +29,27 @@
 #include "virstring.h"
 #include "moment_conf.h"

+/* FIXME: using virObject would allow us to not need this */
+#include "snapshot_conf.h"
+#include "virdomainsnapshotobjlist.h"
+
 #define VIR_FROM_THIS VIR_FROM_DOMAIN

 VIR_LOG_INIT("conf.virdomainmomentobjlist");

+/* Opaque struct */
+struct _virDomainMomentObjList {
+    /* name string -> virDomainMomentObj  mapping
+     * for O(1), lockless lookup-by-name */
+    virHashTable *objs;
+
+    virDomainMomentObj metaroot; /* Special parent of all root snapshots */
+    virDomainMomentObjPtr current; /* The current snapshot, if any */
+
+    virDomainMomentObjListFilter filter;
+};
+
+
 /* Run iter(data) on all direct children of moment, while ignoring all
  * other entries in moments.  Return the number of children
  * visited.  No particular ordering is guaranteed.  */
@@ -163,3 +180,342 @@ virDomainMomentMoveChildren(virDomainMomentObjPtr from,
     from->nchildren = 0;
     from->first_child = NULL;
 }
+
+
+static virDomainMomentObjPtr
+virDomainMomentObjNew(void)
+{
+    virDomainMomentObjPtr snapshot;
+
+    if (VIR_ALLOC(snapshot) < 0)
+        return NULL;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    return snapshot;
+}
+
+static void
+virDomainMomentObjFree(virDomainMomentObjPtr snapshot)
+{
+    if (!snapshot)
+        return;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    /* FIXME: Make this polymorphic by inheriting from virObject */
+    virDomainSnapshotDefFree(virDomainSnapshotObjGetDef(snapshot));
+    VIR_FREE(snapshot);
+}
+
+
+/* Add def to the list and return a matching object, or NULL on error */
+virDomainMomentObjPtr
+virDomainMomentAssignDef(virDomainMomentObjListPtr moments,
+                         virDomainMomentDefPtr def)
+{
+    virDomainMomentObjPtr moment;
+
+    if (virHashLookup(moments->objs, def->name) != NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected domain moment %s already exists"),
+                       def->name);
+        return NULL;
+    }
+
+    if (!(moment = virDomainMomentObjNew()))
+        return NULL;
+    moment->def = def;
+
+    if (virHashAddEntry(moments->objs, moment->def->name, moment) < 0) {
+        VIR_FREE(moment);
+        return NULL;
+    }
+
+    return moment;
+}
+
+
+static void
+virDomainMomentObjListDataFree(void *payload,
+                               const void *name ATTRIBUTE_UNUSED)
+{
+    virDomainMomentObjPtr obj = payload;
+
+    virDomainMomentObjFree(obj);
+}
+
+
+virDomainMomentObjListPtr
+virDomainMomentObjListNew(virDomainMomentObjListFilter filter)
+{
+    virDomainMomentObjListPtr moments;
+
+    if (VIR_ALLOC(moments) < 0)
+        return NULL;
+    moments->objs = virHashCreate(50, virDomainMomentObjListDataFree);
+    if (!moments->objs) {
+        VIR_FREE(moments);
+        return NULL;
+    }
+    moments->filter = filter;
+    return moments;
+}
+
+void
+virDomainMomentObjListFree(virDomainMomentObjListPtr moments)
+{
+    if (!moments)
+        return;
+    virHashFree(moments->objs);
+    VIR_FREE(moments);
+}
+
+
+/* Struct and callback for collecting a list of names of moments that
+ * meet a particular filter. */
+struct virDomainMomentNameData {
+    char **const names;
+    int maxnames;
+    unsigned int flags;
+    int count;
+    bool error;
+    virDomainMomentObjListFilter filter;
+};
+
+static int virDomainMomentObjListCopyNames(void *payload,
+                                           const void *name ATTRIBUTE_UNUSED,
+                                           void *opaque)
+{
+    virDomainMomentObjPtr obj = payload;
+    struct virDomainMomentNameData *data = opaque;
+
+    if (data->error)
+        return 0;
+    /* Caller already sanitized flags.  Filtering on DESCENDANTS was
+     * done by choice of iteration in the caller.  */
+    if ((data->flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) && obj->nchildren)
+        return 0;
+    if ((data->flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES) && !obj->nchildren)
+        return 0;
+
+    if (!data->filter(obj, data->flags))
+        return 0;
+
+    if (data->names && data->count < data->maxnames &&
+        VIR_STRDUP(data->names[data->count], obj->def->name) < 0) {
+        data->error = true;
+        return 0;
+    }
+    data->count++;
+    return 0;
+}
+
+
+int
+virDomainMomentObjListGetNames(virDomainMomentObjListPtr moments,
+                               virDomainMomentObjPtr from,
+                               char **const names,
+                               int maxnames,
+                               unsigned int flags)
+{
+    struct virDomainMomentNameData data = { names, maxnames, flags, 0,
+                                            false, moments->filter };
+    size_t i;
+
+    if (!from) {
+        /* LIST_ROOTS and LIST_DESCENDANTS have the same bit value,
+         * but opposite semantics.  Toggle here to get the correct
+         * traversal on the metaroot.  */
+        flags ^= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
+        from = &moments->metaroot;
+    }
+
+    /* We handle LIST_ROOT/LIST_DESCENDANTS and LIST_TOPOLOGICAL directly,
+     * mask those bits out to determine when we must use the filter callback. */
+    data.flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
+                    VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL);
+
+    /* If this common code is being used, we assume that all snapshots
+     * have metadata, and thus can handle METADATA up front as an
+     * all-or-none filter.  XXX This might not always be true, if we
+     * add the ability to track qcow2 internal snapshots without the
+     * use of metadata.  */
+    if ((data.flags & VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA) ==
+        VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA)
+        return 0;
+    data.flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA;
+
+    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) {
+        /* We could just always do a topological visit; but it is
+         * possible to optimize for less stack usage and time when a
+         * simpler full hashtable visit or counter will do. */
+        if (from->def || (names &&
+                          (flags & VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL)))
+            virDomainMomentForEachDescendant(from,
+                                             virDomainMomentObjListCopyNames,
+                                             &data);
+        else if (names || data.flags)
+            virHashForEach(moments->objs, virDomainMomentObjListCopyNames,
+                           &data);
+        else
+            data.count = virHashSize(moments->objs);
+    } else if (names || data.flags) {
+        virDomainMomentForEachChild(from,
+                                    virDomainMomentObjListCopyNames, &data);
+    } else {
+        data.count = from->nchildren;
+    }
+
+    if (data.error) {
+        for (i = 0; i < data.count; i++)
+            VIR_FREE(names[i]);
+        return -1;
+    }
+
+    return data.count;
+}
+
+
+virDomainMomentObjPtr
+virDomainMomentFindByName(virDomainMomentObjListPtr moments,
+                          const char *name)
+{
+    return name ? virHashLookup(moments->objs, name) : &moments->metaroot;
+}
+
+
+/* Return the current moment, or NULL */
+virDomainMomentObjPtr
+virDomainMomentGetCurrent(virDomainMomentObjListPtr moments)
+{
+    return moments->current;
+}
+
+
+/* Return the current moment's name, or NULL */
+const char *
+virDomainMomentGetCurrentName(virDomainMomentObjListPtr moments)
+{
+    if (moments->current)
+        return moments->current->def->name;
+    return NULL;
+}
+
+
+/* Return true if name matches the current moment */
+bool
+virDomainMomentIsCurrentName(virDomainMomentObjListPtr moments,
+                             const char *name)
+{
+    return moments->current && STREQ(moments->current->def->name, name);
+}
+
+
+/* Update the current moment, using NULL if no current remains */
+void
+virDomainMomentSetCurrent(virDomainMomentObjListPtr moments,
+                          virDomainMomentObjPtr moment)
+{
+    moments->current = moment;
+}
+
+
+/* Return the number of moments in the list */
+int
+virDomainMomentObjListSize(virDomainMomentObjListPtr moments)
+{
+    return virHashSize(moments->objs);
+}
+
+
+/* Remove moment from the list; return true if it was current */
+bool
+virDomainMomentObjListRemove(virDomainMomentObjListPtr moments,
+                             virDomainMomentObjPtr moment)
+{
+    bool ret = moments->current == moment;
+
+    virHashRemoveEntry(moments->objs, moment->def->name);
+    if (ret)
+        moments->current = NULL;
+    return ret;
+}
+
+
+/* Remove all moments tracked in the list */
+void
+virDomainMomentObjListRemoveAll(virDomainMomentObjListPtr moments)
+{
+    virHashRemoveAll(moments->objs);
+    virDomainMomentDropChildren(&moments->metaroot);
+}
+
+
+/* Call iter on each member of the list, in unspecified order */
+int
+virDomainMomentForEach(virDomainMomentObjListPtr moments,
+                       virHashIterator iter,
+                       void *data)
+{
+    return virHashForEach(moments->objs, iter, data);
+}
+
+
+/* Struct and callback function used as a hash table callback; each call
+ * inspects the pre-existing moment->def->parent field, and adjusts
+ * the moment->parent field as well as the parent's child fields to
+ * wire up the hierarchical relations for the given snapshot.  The error
+ * indicator gets set if a parent is missing or a requested parent would
+ * cause a circular parent chain.  */
+struct moment_set_relation {
+    virDomainMomentObjListPtr moments;
+    int err;
+};
+static int
+virDomainMomentSetRelations(void *payload,
+                            const void *name ATTRIBUTE_UNUSED,
+                            void *data)
+{
+    virDomainMomentObjPtr obj = payload;
+    struct moment_set_relation *curr = data;
+    virDomainMomentObjPtr tmp;
+    virDomainMomentObjPtr parent;
+
+    parent = virDomainMomentFindByName(curr->moments, obj->def->parent);
+    if (!parent) {
+        curr->err = -1;
+        parent = &curr->moments->metaroot;
+        VIR_WARN("snapshot %s lacks parent", obj->def->name);
+    } else {
+        tmp = parent;
+        while (tmp && tmp->def) {
+            if (tmp == obj) {
+                curr->err = -1;
+                parent = &curr->moments->metaroot;
+                VIR_WARN("snapshot %s in circular chain", obj->def->name);
+                break;
+            }
+            tmp = tmp->parent;
+        }
+    }
+    virDomainMomentSetParent(obj, parent);
+    return 0;
+}
+
+
+/* Populate parent link and child count of all snapshots, with all
+ * assigned defs having relations starting as 0/NULL. Return 0 on
+ * success, -1 if a parent is missing or if a circular relationship
+ * was requested. */
+int
+virDomainMomentUpdateRelations(virDomainMomentObjListPtr moments)
+{
+    struct moment_set_relation act = { moments, 0 };
+
+    virDomainMomentDropChildren(&moments->metaroot);
+    virHashForEach(moments->objs, virDomainMomentSetRelations, &act);
+    if (act.err)
+        moments->current = NULL;
+    return act.err;
+}
diff --git a/src/conf/virdomainsnapshotobjlist.c b/src/conf/virdomainsnapshotobjlist.c
index 8ecb131176..31ed1c672d 100644
--- a/src/conf/virdomainsnapshotobjlist.c
+++ b/src/conf/virdomainsnapshotobjlist.c
@@ -35,12 +35,7 @@
 VIR_LOG_INIT("conf.virdomainsnapshotobjlist");

 struct _virDomainSnapshotObjList {
-    /* name string -> virDomainMomentObj  mapping
-     * for O(1), lockless lookup-by-name */
-    virHashTable *objs;
-
-    virDomainMomentObj metaroot; /* Special parent of all root snapshots */
-    virDomainMomentObjPtr current; /* The current snapshot, if any */
+    virDomainMomentObjListPtr base;
 };


@@ -72,7 +67,7 @@ virDomainSnapshotObjListParse(const char *xmlStr,
                        _("incorrect flags for bulk parse"));
         return -1;
     }
-    if (virDomainSnapshotObjListSize(snapshots)) {
+    if (virDomainMomentObjListSize(snapshots->base)) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("bulk define of snapshots only possible with "
                          "no existing snapshot"));
@@ -143,7 +138,7 @@ virDomainSnapshotObjListParse(const char *xmlStr,
     if (ret < 0) {
         /* There were no snapshots before this call; so on error, just
          * blindly delete anything created before the failure. */
-        virDomainSnapshotObjListRemoveAll(snapshots);
+        virDomainMomentObjListRemoveAll(snapshots->base);
     }
     xmlXPathFreeContext(ctxt);
     xmlFreeDoc(xml);
@@ -211,55 +206,14 @@ virDomainSnapshotObjListFormat(virBufferPtr buf,
 }


-/* Snapshot Obj functions */
-static virDomainMomentObjPtr virDomainMomentObjNew(void)
+virDomainMomentObjPtr
+virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
+                           virDomainSnapshotDefPtr def)
 {
-    virDomainMomentObjPtr snapshot;
-
-    if (VIR_ALLOC(snapshot) < 0)
-        return NULL;
-
-    VIR_DEBUG("obj=%p", snapshot);
-
-    return snapshot;
-}
-
-static void virDomainMomentObjFree(virDomainMomentObjPtr snapshot)
-{
-    if (!snapshot)
-        return;
-
-    VIR_DEBUG("obj=%p", snapshot);
-
-    virDomainSnapshotDefFree(virDomainSnapshotObjGetDef(snapshot));
-    VIR_FREE(snapshot);
+    return virDomainMomentAssignDef(snapshots->base, &def->common);
 }

-virDomainMomentObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
-                                                 virDomainSnapshotDefPtr def)
-{
-    virDomainMomentObjPtr snap;
-
-    if (virHashLookup(snapshots->objs, def->common.name) != NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("unexpected domain snapshot %s already exists"),
-                       def->common.name);
-        return NULL;
-    }
-
-    if (!(snap = virDomainMomentObjNew()))
-        return NULL;
-    snap->def = &def->common;
-
-    if (virHashAddEntry(snapshots->objs, snap->def->name, snap) < 0) {
-        VIR_FREE(snap);
-        return NULL;
-    }
-
-    return snap;
-}

-/* Snapshot Obj List functions */
 static bool
 virDomainSnapshotFilter(virDomainMomentObjPtr obj,
                         unsigned int flags)
@@ -292,76 +246,30 @@ virDomainSnapshotFilter(virDomainMomentObjPtr obj,
 }


-static void
-virDomainSnapshotObjListDataFree(void *payload,
-                                 const void *name ATTRIBUTE_UNUSED)
-{
-    virDomainMomentObjPtr obj = payload;
-
-    virDomainMomentObjFree(obj);
-}
-
 virDomainSnapshotObjListPtr
 virDomainSnapshotObjListNew(void)
 {
     virDomainSnapshotObjListPtr snapshots;
+
     if (VIR_ALLOC(snapshots) < 0)
         return NULL;
-    snapshots->objs = virHashCreate(50, virDomainSnapshotObjListDataFree);
-    if (!snapshots->objs) {
+    snapshots->base = virDomainMomentObjListNew(virDomainSnapshotFilter);
+    if (!snapshots->base) {
         VIR_FREE(snapshots);
         return NULL;
     }
     return snapshots;
 }

+
 void
 virDomainSnapshotObjListFree(virDomainSnapshotObjListPtr snapshots)
 {
-    if (!snapshots)
-        return;
-    virHashFree(snapshots->objs);
+    virDomainMomentObjListFree(snapshots->base);
     VIR_FREE(snapshots);
 }


-struct virDomainMomentNameData {
-    char **const names;
-    int maxnames;
-    unsigned int flags;
-    int count;
-    bool error;
-    virDomainMomentObjListFilter filter;
-};
-
-static int virDomainMomentObjListCopyNames(void *payload,
-                                           const void *name ATTRIBUTE_UNUSED,
-                                           void *opaque)
-{
-    virDomainMomentObjPtr obj = payload;
-    struct virDomainMomentNameData *data = opaque;
-
-    if (data->error)
-        return 0;
-    /* Caller already sanitized flags.  Filtering on DESCENDANTS was
-     * done by choice of iteration in the caller.  */
-    if ((data->flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) && obj->nchildren)
-        return 0;
-    if ((data->flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES) && !obj->nchildren)
-        return 0;
-
-    if (data->filter(obj, data->flags))
-        return 0;
-
-    if (data->names && data->count < data->maxnames &&
-        VIR_STRDUP(data->names[data->count], obj->def->name) < 0) {
-        data->error = true;
-        return 0;
-    }
-    data->count++;
-    return 0;
-}
-
 int
 virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
                                  virDomainMomentObjPtr from,
@@ -369,73 +277,29 @@ virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
                                  int maxnames,
                                  unsigned int flags)
 {
-    struct virDomainMomentNameData data = { names, maxnames, flags, 0,
-                                            false, virDomainSnapshotFilter };
-    size_t i;
-
-    if (!from) {
-        /* LIST_ROOTS and LIST_DESCENDANTS have the same bit value,
-         * but opposite semantics.  Toggle here to get the correct
-         * traversal on the metaroot.  */
-        flags ^= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
-        from = &snapshots->metaroot;
-    }
-
-    /* We handle LIST_ROOT/LIST_DESCENDANTS and LIST_TOPOLOGICAL directly,
-     * mask those bits out to determine when we must use the filter callback. */
-    data.flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
-                    VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL);
-
     /* If this common code is being used, we assume that all snapshots
      * have metadata, and thus can handle METADATA up front as an
      * all-or-none filter.  XXX This might not always be true, if we
      * add the ability to track qcow2 internal snapshots without the
      * use of metadata.  */
-    if ((data.flags & VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA) ==
+    if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA) ==
         VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA)
         return 0;
-    data.flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA;
+    flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_METADATA;

     /* For ease of coding the visitor, it is easier to zero each group
      * where all of the bits are set.  */
-    if ((data.flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES) ==
+    if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES) ==
         VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES)
-        data.flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES;
-    if ((data.flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) ==
+        flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES;
+    if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) ==
         VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS)
-        data.flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS;
-    if ((data.flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION) ==
+        flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS;
+    if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION) ==
         VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION)
-        data.flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION;
-
-    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) {
-        /* We could just always do a topological visit; but it is
-         * possible to optimize for less stack usage and time when a
-         * simpler full hashtable visit or counter will do. */
-        if (from->def || (names &&
-                          (flags & VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL)))
-            virDomainMomentForEachDescendant(from,
-                                             virDomainMomentObjListCopyNames,
-                                             &data);
-        else if (names || data.flags)
-            virHashForEach(snapshots->objs, virDomainMomentObjListCopyNames,
-                           &data);
-        else
-            data.count = virHashSize(snapshots->objs);
-    } else if (names || data.flags) {
-        virDomainMomentForEachChild(from,
-                                    virDomainMomentObjListCopyNames, &data);
-    } else {
-        data.count = from->nchildren;
-    }
-
-    if (data.error) {
-        for (i = 0; i < data.count; i++)
-            VIR_FREE(names[i]);
-        return -1;
-    }
-
-    return data.count;
+        flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION;
+    return virDomainMomentObjListGetNames(snapshots->base, from, names,
+                                          maxnames, flags);
 }

 int
@@ -446,19 +310,12 @@ virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots,
     return virDomainSnapshotObjListGetNames(snapshots, from, NULL, 0, flags);
 }

+
 virDomainMomentObjPtr
 virDomainSnapshotFindByName(virDomainSnapshotObjListPtr snapshots,
                             const char *name)
 {
-    return name ? virHashLookup(snapshots->objs, name) : &snapshots->metaroot;
-}
-
-
-/* Return the number of objects currently in the list */
-int
-virDomainSnapshotObjListSize(virDomainSnapshotObjListPtr snapshots)
-{
-    return virHashSize(snapshots->objs);
+    return virDomainMomentFindByName(snapshots->base, name);
 }


@@ -466,7 +323,7 @@ virDomainSnapshotObjListSize(virDomainSnapshotObjListPtr snapshots)
 virDomainMomentObjPtr
 virDomainSnapshotGetCurrent(virDomainSnapshotObjListPtr snapshots)
 {
-    return snapshots->current;
+    return virDomainMomentGetCurrent(snapshots->base);
 }


@@ -474,9 +331,7 @@ virDomainSnapshotGetCurrent(virDomainSnapshotObjListPtr snapshots)
 const char *
 virDomainSnapshotGetCurrentName(virDomainSnapshotObjListPtr snapshots)
 {
-    if (snapshots->current)
-        return snapshots->current->def->name;
-    return NULL;
+    return virDomainMomentGetCurrentName(snapshots->base);
 }


@@ -485,7 +340,7 @@ bool
 virDomainSnapshotIsCurrentName(virDomainSnapshotObjListPtr snapshots,
                                const char *name)
 {
-    return snapshots->current && STREQ(snapshots->current->def->name, name);
+    return virDomainMomentIsCurrentName(snapshots->base, name);
 }


@@ -494,7 +349,7 @@ void
 virDomainSnapshotSetCurrent(virDomainSnapshotObjListPtr snapshots,
                             virDomainMomentObjPtr snapshot)
 {
-    snapshots->current = snapshot;
+    virDomainMomentSetCurrent(snapshots->base, snapshot);
 }


@@ -502,19 +357,7 @@ virDomainSnapshotSetCurrent(virDomainSnapshotObjListPtr snapshots,
 bool virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
                                     virDomainMomentObjPtr snapshot)
 {
-    bool ret = snapshots->current == snapshot;
-    virHashRemoveEntry(snapshots->objs, snapshot->def->name);
-    if (ret)
-        snapshots->current = NULL;
-    return ret;
-}
-
-/* Remove all snapshots tracked in the list */
-void
-virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjListPtr snapshots)
-{
-    virHashRemoveAll(snapshots->objs);
-    virDomainMomentDropChildren(&snapshots->metaroot);
+    return virDomainMomentObjListRemove(snapshots->base, snapshot);
 }


@@ -523,51 +366,10 @@ virDomainSnapshotForEach(virDomainSnapshotObjListPtr snapshots,
                          virHashIterator iter,
                          void *data)
 {
-    return virHashForEach(snapshots->objs, iter, data);
+    return virDomainMomentForEach(snapshots->base, iter, data);
 }


-/* Struct and callback function used as a hash table callback; each call
- * inspects the pre-existing snapshot->def->parent field, and adjusts
- * the snapshot->parent field as well as the parent's child fields to
- * wire up the hierarchical relations for the given snapshot.  The error
- * indicator gets set if a parent is missing or a requested parent would
- * cause a circular parent chain.  */
-struct moment_set_relation {
-    virDomainSnapshotObjListPtr snapshots;
-    int err;
-};
-static int
-virDomainMomentSetRelations(void *payload,
-                            const void *name ATTRIBUTE_UNUSED,
-                            void *data)
-{
-    virDomainMomentObjPtr obj = payload;
-    struct moment_set_relation *curr = data;
-    virDomainMomentObjPtr tmp;
-    virDomainMomentObjPtr parent;
-
-    parent = virDomainSnapshotFindByName(curr->snapshots, obj->def->parent);
-    if (!parent) {
-        curr->err = -1;
-        parent = &curr->snapshots->metaroot;
-        VIR_WARN("snapshot %s lacks parent", obj->def->name);
-    } else {
-        tmp = parent;
-        while (tmp && tmp->def) {
-            if (tmp == obj) {
-                curr->err = -1;
-                parent = &curr->snapshots->metaroot;
-                VIR_WARN("snapshot %s in circular chain", obj->def->name);
-                break;
-            }
-            tmp = tmp->parent;
-        }
-    }
-    virDomainMomentSetParent(obj, parent);
-    return 0;
-}
-
 /* Populate parent link and child count of all snapshots, with all
  * assigned defs having relations starting as 0/NULL. Return 0 on
  * success, -1 if a parent is missing or if a circular relationship
@@ -575,13 +377,7 @@ virDomainMomentSetRelations(void *payload,
 int
 virDomainSnapshotUpdateRelations(virDomainSnapshotObjListPtr snapshots)
 {
-    struct moment_set_relation act = { snapshots, 0 };
-
-    virDomainMomentDropChildren(&snapshots->metaroot);
-    virHashForEach(snapshots->objs, virDomainMomentSetRelations, &act);
-    if (act.err)
-        snapshots->current = NULL;
-    return act.err;
+    return virDomainMomentUpdateRelations(snapshots->base);
 }


-- 
2.20.1




More information about the libvir-list mailing list