Snapshot internal methods.

Signed-off-by: Chris Lalancette <clalance@redhat.com>
This commit is contained in:
Chris Lalancette 2010-04-02 10:41:30 -04:00
parent 2f992d4be4
commit 9b55a52b4f
3 changed files with 430 additions and 0 deletions

View File

@ -28,6 +28,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/time.h>
#include "virterror_internal.h"
#include "datatypes.h"
@ -43,6 +44,7 @@
#include "network.h"
#include "macvtap.h"
#include "nwfilter_conf.h"
#include "ignore-value.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@ -744,6 +746,8 @@ static void virDomainObjFree(virDomainObjPtr dom)
virMutexDestroy(&dom->lock);
virDomainSnapshotObjListDeinit(&dom->snapshots);
VIR_FREE(dom);
}
@ -796,6 +800,8 @@ static virDomainObjPtr virDomainObjNew(virCapsPtr caps)
domain->state = VIR_DOMAIN_SHUTOFF;
domain->refs = 1;
virDomainSnapshotObjListInit(&domain->snapshots);
VIR_DEBUG("obj=%p", domain);
return domain;
}
@ -6558,4 +6564,363 @@ 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;
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;
gettimeofday(&tv, NULL);
def->name = virXPathString("string(./name)", ctxt);
if (def->name == NULL)
ignore_value(virAsprintf(&def->name, "%ld", tv.tv_sec));
if (def->name == NULL) {
virReportOOMError();
goto cleanup;
}
def->description = virXPathString("string(./description)", ctxt);
if (!newSnapshot) {
if (virXPathLong("string(./creationTime)", ctxt,
&def->creationTime) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing creationTime from existing snapshot"));
goto cleanup;
}
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;
}
if (virXPathLong("string(./active)", ctxt, &def->active) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not find 'active' element"));
goto cleanup;
}
}
else
def->creationTime = tv.tv_sec;
ret = def;
cleanup:
VIR_FREE(creation);
VIR_FREE(state);
xmlXPathFreeContext(ctxt);
if (ret == NULL)
virDomainSnapshotDefFree(def);
xmlFreeDoc(xml);
return ret;
}
char *virDomainSnapshotDefFormat(char *domain_uuid,
virDomainSnapshotDefPtr def,
int internal)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
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");
}
virBufferVSprintf(&buf, " <creationTime>%ld</creationTime>\n",
def->creationTime);
virBufferAddLit(&buf, " <domain>\n");
virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", domain_uuid);
virBufferAddLit(&buf, " </domain>\n");
if (internal)
virBufferVSprintf(&buf, " <active>%ld</active>\n", def->active);
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 */

View File

@ -741,6 +741,58 @@ 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;
long active;
};
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,
int internal);
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;
@ -828,6 +880,9 @@ struct _virDomainObj {
virDomainDefPtr def; /* The current definition */
virDomainDefPtr newDef; /* New definition to activate at shutdown */
virDomainSnapshotObjList snapshots;
virDomainSnapshotObjPtr current_snapshot;
void *privateData;
void (*privateDataFreeFunc)(void *);
};

View File

@ -206,6 +206,16 @@ virDomainTimerTickpolicyTypeToString;
virDomainTimerTickpolicyTypeFromString;
virDomainTimerModeTypeToString;
virDomainTimerModeTypeFromString;
virDomainSnapshotObjListGetNames;
virDomainSnapshotObjListNum;
virDomainSnapshotFindByName;
virDomainSnapshotObjListAdd;
virDomainSnapshotObjListRemove;
virDomainSnapshotHasChildren;
virDomainSnapshotObjUnref;
virDomainSnapshotDefParseString;
virDomainSnapshotDefFormat;
virDomainSnapshotAssignDef;
# domain_event.h