提交 dc8d3dc6 编写于 作者: E Eric Blake

snapshot: Create new virDomainMomentObjList type

The new code here very heavily resembles the code in
virDomainSnapshotObjList. There are still a couple of spots that are
tied a little too heavily to snapshots (the free function lacks a
polymorphic cleanup until we refactor code to use virObject; and an
upcoming patch will add internal VIR_DOMAIN_MOMENT_LIST flags to
replace the snapshot flag bits), but in general this is fairly close
to the state needed to add checkpoint lists.
Signed-off-by: NEric Blake <eblake@redhat.com>
Reviewed-by: NJohn Ferlan <jferlan@redhat.com>
上级 5d23cd1c
......@@ -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;
......
......@@ -29,10 +29,25 @@
#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 moments */
virDomainMomentObjPtr current; /* The current moment, if any */
};
/* 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. */
......@@ -165,3 +180,347 @@ virDomainMomentMoveChildren(virDomainMomentObjPtr from,
from->nchildren = 0;
from->first_child = NULL;
}
static virDomainMomentObjPtr
virDomainMomentObjNew(void)
{
virDomainMomentObjPtr moment;
if (VIR_ALLOC(moment) < 0)
return NULL;
VIR_DEBUG("obj=%p", moment);
return moment;
}
static void
virDomainMomentObjFree(virDomainMomentObjPtr moment)
{
if (!moment)
return;
VIR_DEBUG("obj=%p", moment);
/* FIXME: Make this polymorphic by inheriting from virObject */
virDomainSnapshotDefFree(virDomainSnapshotObjGetDef(moment));
VIR_FREE(moment);
}
/* 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;
if (virHashAddEntry(moments->objs, moment->def->name, moment) < 0) {
VIR_FREE(moment);
return NULL;
}
moment->def = def;
return moment;
}
static void
virDomainMomentObjListDataFree(void *payload,
const void *name ATTRIBUTE_UNUSED)
{
virDomainMomentObjPtr obj = payload;
virDomainMomentObjFree(obj);
}
virDomainMomentObjListPtr
virDomainMomentObjListNew(void)
{
virDomainMomentObjListPtr moments;
if (VIR_ALLOC(moments) < 0)
return NULL;
moments->objs = virHashCreate(50, virDomainMomentObjListDataFree);
if (!moments->objs) {
VIR_FREE(moments);
return NULL;
}
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. */
/* TODO: Create VIR_DOMAIN_MOMENT_LIST names */
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,
virDomainMomentObjListFilter filter)
{
struct virDomainMomentNameData data = { names, maxnames, flags, 0,
false, 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. */
/* TODO: Create VIR_DOMAIN_MOMENT_LIST names */
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 moments
* 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, in which case this check should move into the
* filter callback. */
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 moment. 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("moment %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("moment %s in circular chain", obj->def->name);
break;
}
tmp = tmp->parent;
}
}
virDomainMomentSetParent(obj, parent);
return 0;
}
/* Populate parent link and child count of all moments, 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;
}
......@@ -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,33 @@ void virDomainMomentMoveChildren(virDomainMomentObjPtr from,
void virDomainMomentSetParent(virDomainMomentObjPtr moment,
virDomainMomentObjPtr parent);
virDomainMomentObjListPtr virDomainMomentObjListNew(void);
void virDomainMomentObjListFree(virDomainMomentObjListPtr moments);
virDomainMomentObjPtr virDomainMomentAssignDef(virDomainMomentObjListPtr moments,
virDomainMomentDefPtr def);
int virDomainMomentObjListGetNames(virDomainMomentObjListPtr moments,
virDomainMomentObjPtr from,
char **const names,
int maxnames,
unsigned int flags,
virDomainMomentObjListFilter filter);
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 */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册