[libvirt] [RFC PATCH 4/8] Snapshot internal methods.

Chris Lalancette clalance at redhat.com
Thu Apr 1 22:07:23 UTC 2010


Signed-off-by: Chris Lalancette <clalance at redhat.com>
---
 src/conf/domain_conf.c   |  402 ++++++++++++++++++++++++++++++++++++++++++++--
 src/conf/domain_conf.h   |   53 ++++++
 src/libvirt_private.syms |   10 ++
 3 files changed, 455 insertions(+), 10 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e260dce..1971b9a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/time.h>
 
 #include "virterror_internal.h"
 #include "datatypes.h"
@@ -742,6 +743,8 @@ static void virDomainObjFree(virDomainObjPtr dom)
 
     virMutexDestroy(&dom->lock);
 
+    virDomainSnapshotObjListDeinit(&dom->snapshots);
+
     VIR_FREE(dom);
 }
 
@@ -794,6 +797,8 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
     domain->state = VIR_DOMAIN_SHUTOFF;
     domain->refs = 1;
 
+    virDomainSnapshotObjListInit(&domain->snapshots);
+
     VIR_DEBUG("obj=%p", domain);
     return domain;
 }
@@ -6096,22 +6101,25 @@ static virDomainObjPtr virDomainLoadConfig(virCapsPtr caps,
 
     if ((configFile = virDomainConfigFile(configDir, name)) == NULL)
         goto error;
-    if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
-        goto error;
-
-    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
-        goto error;
-
     if (!(def = virDomainDefParseFile(caps, configFile,
                                       VIR_DOMAIN_XML_INACTIVE)))
         goto error;
 
-    if ((dom = virDomainFindByName(doms, def->name))) {
-        virDomainObjUnlock(dom);
-        dom = NULL;
-        newVM = 0;
+    /* if the domain is already in our hashtable, we don't need to do
+     * anything further
+     */
+    if ((dom = virDomainFindByUUID(doms, def->uuid))) {
+        VIR_FREE(configFile);
+        virDomainDefFree(def);
+        return dom;
     }
 
+    if ((autostartLink = virDomainConfigFile(autostartDir, name)) == NULL)
+        goto error;
+
+    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
+        goto error;
+
     if (!(dom = virDomainAssignDef(caps, doms, def, false)))
         goto error;
 
@@ -6509,4 +6517,378 @@ cleanup:
     return -1;
 }
 
+/* Snapshot Def functions */
+void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->name);
+    VIR_FREE(def->description);
+    VIR_FREE(def->parent);
+    VIR_FREE(def);
+}
+
+virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
+                                                        int newSnapshot)
+{
+    xmlXPathContextPtr ctxt = NULL;
+    xmlDocPtr xml = NULL;
+    xmlNodePtr root;
+    virDomainSnapshotDefPtr def = NULL;
+    virDomainSnapshotDefPtr ret = NULL;
+    char *creation = NULL, *state = NULL;
+    struct timeval tv;
+    struct tm time_info;
+    char timestr[100];
+
+    xml = virXMLParse(NULL, xmlStr, "domainsnapshot.xml");
+    if (!xml) {
+        virDomainReportError(VIR_ERR_XML_ERROR,
+                             "%s",_("failed to parse snapshot xml document"));
+        return NULL;
+    }
+
+    if ((root = xmlDocGetRootElement(xml)) == NULL) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("missing root element"));
+        goto cleanup;
+    }
+
+    if (!xmlStrEqual(root->name, BAD_CAST "domainsnapshot")) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("incorrect root element"));
+        goto cleanup;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ctxt->node = root;
+
+    def->name = virXPathString("string(./name)", ctxt);
+    if (def->name == NULL) {
+        /* make up a name */
+        gettimeofday(&tv, NULL);
+        localtime_r(&tv.tv_sec, &time_info);
+        strftime(timestr, sizeof(timestr), "%F_%T", &time_info);
+        def->name = strdup(timestr);
+    }
+    if (def->name == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->description = virXPathString("string(./description)", ctxt);
+
+    if (!newSnapshot) {
+        creation = virXPathString("string(./creationTime)", ctxt);
+        if (creation == NULL) {
+            /* there was no creation time in an existing snapshot; this
+             * should never happen
+             */
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("missing creationTime from existing snapshot"));
+            goto cleanup;
+        }
+
+        if (strptime(creation, "%Y-%m-%d_%T", &time_info) == NULL) {
+            /* we saw a creation time we couldn't parse.  We shouldn't
+             * ever see this, so throw an error
+             */
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("Could not convert '%s' to a time value"),
+                                 creation);
+            goto cleanup;
+        }
+        def->creationTime = mktime(&time_info);
+
+        def->parent = virXPathString("string(./parent/name)", ctxt);
+
+        state = virXPathString("string(./state)", ctxt);
+        if (state == NULL) {
+            /* there was no state in an existing snapshot; this
+             * should never happen
+             */
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                 _("missing state from existing snapshot"));
+            goto cleanup;
+        }
+        def->state = virDomainStateTypeFromString(state);
+        if (def->state < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("Invalid state '%s' in domain snapshot XML"),
+                                 state);
+            goto cleanup;
+        }
+    }
+    else {
+        gettimeofday(&tv, NULL);
+        def->creationTime = tv.tv_sec;
+    }
+
+    ret = def;
+
+cleanup:
+    VIR_FREE(creation);
+    VIR_FREE(state);
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    if (ret == NULL)
+        virDomainSnapshotDefFree(def);
+    xmlFreeDoc(xml);
+
+    return ret;
+}
+
+char *virDomainSnapshotDefFormat(char *domain_uuid,
+                                 virDomainSnapshotDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char timestr[100];
+    struct tm time_info;
+
+    virBufferAddLit(&buf, "<domainsnapshot>\n");
+    virBufferVSprintf(&buf, "  <name>%s</name>\n", def->name);
+    if (def->description)
+        virBufferVSprintf(&buf, "  <description>%s</description>\n",
+                          def->description);
+    virBufferVSprintf(&buf, "  <state>%s</state>\n",
+                      virDomainStateTypeToString(def->state));
+    if (def->parent) {
+        virBufferAddLit(&buf, "  <parent>\n");
+        virBufferVSprintf(&buf, "    <name>%s</name>\n", def->parent);
+        virBufferAddLit(&buf, "  </parent>\n");
+    }
+    localtime_r(&def->creationTime, &time_info);
+    strftime(timestr, sizeof(timestr), "%F_%T", &time_info);
+    virBufferVSprintf(&buf, "  <creationTime>%s</creationTime>\n", timestr);
+    virBufferAddLit(&buf, "  <domain>\n");
+    virBufferVSprintf(&buf, "    <uuid>%s</uuid>\n", domain_uuid);
+    virBufferAddLit(&buf, "  </domain>\n");
+    virBufferAddLit(&buf, "</domainsnapshot>\n");
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+/* Snapshot Obj functions */
+static virDomainSnapshotObjPtr virDomainSnapshotObjNew(void)
+{
+    virDomainSnapshotObjPtr snapshot;
+
+    if (VIR_ALLOC(snapshot) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    snapshot->refs = 1;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    return snapshot;
+}
+
+static void virDomainSnapshotObjFree(virDomainSnapshotObjPtr snapshot)
+{
+    if (!snapshot)
+        return;
+
+    VIR_DEBUG("obj=%p", snapshot);
+
+    virDomainSnapshotDefFree(snapshot->def);
+}
+
+int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot)
+{
+    snapshot->refs--;
+    VIR_DEBUG("obj=%p refs=%d", snapshot, snapshot->refs);
+    if (snapshot->refs == 0) {
+        virDomainSnapshotObjFree(snapshot);
+        return 0;
+    }
+    return snapshot->refs;
+}
+
+virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
+                                                   const virDomainSnapshotDefPtr def)
+{
+    virDomainSnapshotObjPtr snap;
+
+    if (virHashLookup(snapshots->objs, def->name) != NULL) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected domain snapshot %s already exists"),
+                             def->name);
+        return NULL;
+    }
+
+    if (!(snap = virDomainSnapshotObjNew()))
+        return NULL;
+    snap->def = def;
+
+    if (virHashAddEntry(snapshots->objs, snap->def->name, snap) < 0) {
+        VIR_FREE(snap);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return snap;
+}
+
+/* Snapshot Obj List functions */
+int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr snapshots)
+{
+    snapshots->objs = virHashCreate(50);
+    if (!snapshots->objs) {
+        virReportOOMError();
+        return -1;
+    }
+    return 0;
+}
+
+static void virDomainSnapshotObjListDeallocator(void *payload,
+                                                const char *name ATTRIBUTE_UNUSED)
+{
+    virDomainSnapshotObjPtr obj = payload;
+
+    virDomainSnapshotObjUnref(obj);
+}
+
+void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr snapshots)
+{
+    if (snapshots->objs)
+        virHashFree(snapshots->objs, virDomainSnapshotObjListDeallocator);
+}
+
+struct virDomainSnapshotNameData {
+    int oom;
+    int numnames;
+    int maxnames;
+    char **const names;
+};
+
+static void virDomainSnapshotObjListCopyNames(void *payload,
+                                              const char *name ATTRIBUTE_UNUSED,
+                                              void *opaque)
+{
+    virDomainSnapshotObjPtr obj = payload;
+    struct virDomainSnapshotNameData *data = opaque;
+
+    if (data->oom)
+        return;
+
+    if (data->numnames < data->maxnames) {
+        if (!(data->names[data->numnames] = strdup(obj->def->name)))
+            data->oom = 1;
+        else
+            data->numnames++;
+    }
+}
+
+int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
+                                     char **const names, int maxnames)
+{
+    struct virDomainSnapshotNameData data = { 0, 0, maxnames, names };
+    int i;
+
+    virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames, &data);
+    if (data.oom) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    return data.numnames;
+
+cleanup:
+    for (i = 0; i < data.numnames; i++)
+        VIR_FREE(data.names[i]);
+    return -1;
+}
+
+static void virDomainSnapshotObjListCount(void *payload ATTRIBUTE_UNUSED,
+                                          const char *name ATTRIBUTE_UNUSED,
+                                          void *data)
+{
+    int *count = data;
+
+    (*count)++;
+}
+
+int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots)
+{
+    int count = 0;
+
+    virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &count);
+
+    return count;
+}
+
+static int virDomainSnapshotObjListSearchName(const void *payload,
+                                              const char *name ATTRIBUTE_UNUSED,
+                                              const void *data)
+{
+    virDomainSnapshotObjPtr obj = (virDomainSnapshotObjPtr)payload;
+    int want = 0;
+
+    if (STREQ(obj->def->name, (const char *)data))
+        want = 1;
+
+    return want;
+}
+
+virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
+                                                    const char *name)
+{
+    return virHashSearch(snapshots->objs, virDomainSnapshotObjListSearchName, name);
+}
+
+void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
+                                    virDomainSnapshotObjPtr snapshot)
+{
+    virHashRemoveEntry(snapshots->objs, snapshot->def->name,
+                       virDomainSnapshotObjListDeallocator);
+}
+
+struct snapshot_has_children {
+    char *name;
+    int number;
+};
+
+static void virDomainSnapshotCountChildren(void *payload,
+                                           const char *name ATTRIBUTE_UNUSED,
+                                           void *data)
+{
+    virDomainSnapshotObjPtr obj = payload;
+    struct snapshot_has_children *curr = data;
+
+    if (obj->def->parent && STREQ(obj->def->parent, curr->name))
+        curr->number++;
+}
+
+int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
+                                virDomainSnapshotObjListPtr snapshots)
+{
+    struct snapshot_has_children children;
+
+    children.name = snap->def->name;
+    children.number = 0;
+    virHashForEach(snapshots->objs, virDomainSnapshotCountChildren, &children);
+
+    return children.number;
+}
+
+
 #endif /* ! PROXY */
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 023196f..8d5276b 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -729,6 +729,55 @@ struct _virDomainClockDef {
 
 # define VIR_DOMAIN_CPUMASK_LEN 1024
 
+
+/* Snapshot state */
+typedef struct _virDomainSnapshotDef virDomainSnapshotDef;
+typedef virDomainSnapshotDef *virDomainSnapshotDefPtr;
+struct _virDomainSnapshotDef {
+    char *name;
+    char *description;
+    char *parent;
+    time_t creationTime;
+    int state;
+};
+
+typedef struct _virDomainSnapshotObj virDomainSnapshotObj;
+typedef virDomainSnapshotObj *virDomainSnapshotObjPtr;
+struct _virDomainSnapshotObj {
+    int refs;
+
+    virDomainSnapshotDefPtr def;
+};
+
+typedef struct _virDomainSnapshotObjList virDomainSnapshotObjList;
+typedef virDomainSnapshotObjList *virDomainSnapshotObjListPtr;
+struct _virDomainSnapshotObjList {
+    /* name string -> virDomainSnapshotObj  mapping
+     * for O(1), lockless lookup-by-name */
+    virHashTable *objs;
+};
+
+virDomainSnapshotDefPtr virDomainSnapshotDefParseString(const char *xmlStr,
+                                                        int newSnapshot);
+void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def);
+char *virDomainSnapshotDefFormat(char *domain_uuid,
+                                 virDomainSnapshotDefPtr def);
+virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr snapshots,
+                                                   const virDomainSnapshotDefPtr def);
+
+int virDomainSnapshotObjListInit(virDomainSnapshotObjListPtr objs);
+void virDomainSnapshotObjListDeinit(virDomainSnapshotObjListPtr objs);
+int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
+                                     char **const names, int maxnames);
+int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots);
+virDomainSnapshotObjPtr virDomainSnapshotFindByName(const virDomainSnapshotObjListPtr snapshots,
+                                                    const char *name);
+void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
+                                    virDomainSnapshotObjPtr snapshot);
+int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot);
+int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
+                                virDomainSnapshotObjListPtr snapshots);
+
 /* Guest VM main configuration */
 typedef struct _virDomainDef virDomainDef;
 typedef virDomainDef *virDomainDefPtr;
@@ -798,6 +847,8 @@ struct _virDomainDef {
     virSecurityLabelDef seclabel;
     virDomainWatchdogDefPtr watchdog;
     virCPUDefPtr cpu;
+
+    virDomainSnapshotDefPtr current_snapshot;
 };
 
 /* Guest VM runtime state */
@@ -816,6 +867,8 @@ struct _virDomainObj {
     virDomainDefPtr def; /* The current definition */
     virDomainDefPtr newDef; /* New definition to activate at shutdown */
 
+    virDomainSnapshotObjList snapshots;
+
     void *privateData;
     void (*privateDataFreeFunc)(void *);
 };
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c402720..2bdd97b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -206,6 +206,16 @@ virDomainTimerTickpolicyTypeToString;
 virDomainTimerTickpolicyTypeFromString;
 virDomainTimerModeTypeToString;
 virDomainTimerModeTypeFromString;
+virDomainSnapshotObjListGetNames;
+virDomainSnapshotObjListNum;
+virDomainSnapshotFindByName;
+virDomainSnapshotObjListAdd;
+virDomainSnapshotObjListRemove;
+virDomainSnapshotHasChildren;
+virDomainSnapshotObjUnref;
+virDomainSnapshotDefParseString;
+virDomainSnapshotDefFormat;
+virDomainSnapshotAssignDef;
 
 
 # domain_event.h
-- 
1.6.6.1




More information about the libvir-list mailing list