[libvirt] [PATCH 3/4] snapshot: take advantage of new relations
Daniel Veillard
veillard at redhat.com
Mon Oct 10 03:02:41 UTC 2011
On Fri, Oct 07, 2011 at 06:05:56PM -0600, Eric Blake wrote:
> Among other improvements, virDomainSnapshotForEachDescendant is
> changed from iterative O(n^2) to recursive O(n). A bit better
> than the O(n^3) implementation in virsh snapshot-list!
>
> * src/conf/domain_conf.c (virDomainSnapshotObjListNum)
> (virDomainSnapshotObjListNumFrom)
> (virDomainSnapshotObjeListGetNames, virDomainSnapshotForEachChild)
> (virDomainSnapshotForEachDescendant): Optimize.
> (virDomainSnapshotActOnDescendant): Tweak.
> (virDomainSnapshotActOnChild, virDomainSnapshotMarkDescendant):
> Delete, now that they are unused.
> ---
> src/conf/domain_conf.c | 148 ++++++++++++++----------------------------------
> 1 files changed, 43 insertions(+), 105 deletions(-)
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index d4e127d..e77257a 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -12163,10 +12163,21 @@ int virDomainSnapshotObjListGetNames(virDomainSnapshotObjListPtr snapshots,
> char **const names, int maxnames,
> unsigned int flags)
> {
> - struct virDomainSnapshotNameData data = { 0, 0, maxnames, names, flags };
> + struct virDomainSnapshotNameData data = { 0, 0, maxnames, names, 0 };
> int i;
>
> - virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames, &data);
> + data.flags = flags & ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
> +
> + if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) {
> + virHashForEach(snapshots->objs, virDomainSnapshotObjListCopyNames,
> + &data);
> + } else {
> + virDomainSnapshotObjPtr root = snapshots->first_root;
> + while (root) {
> + virDomainSnapshotObjListCopyNames(root, root->def->name, &data);
> + root = root->sibling;
> + }
> + }
> if (data.oom) {
> virReportOOMError();
> goto cleanup;
> @@ -12231,9 +12242,21 @@ static void virDomainSnapshotObjListCount(void *payload,
> int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots,
> unsigned int flags)
> {
> - struct virDomainSnapshotNumData data = { 0, flags };
> + struct virDomainSnapshotNumData data = { 0, 0 };
>
> - virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &data);
> + data.flags = flags & ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
> +
> + if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) {
> + virHashForEach(snapshots->objs, virDomainSnapshotObjListCount, &data);
> + } else if (data.flags) {
> + virDomainSnapshotObjPtr root = snapshots->first_root;
> + while (root) {
> + virDomainSnapshotObjListCount(root, root->def->name, &data);
> + root = root->sibling;
> + }
I was just wondering if a data structure with a meta-root snapshot
and unifying first_root as a first_children on that meta-root wouldn't
lead to simpler code overall.
> + } else {
> + data.count = snapshots->nroots;
> + }
>
> return data.count;
> }
> @@ -12251,9 +12274,11 @@ virDomainSnapshotObjListNumFrom(virDomainSnapshotObjPtr snapshot,
> virDomainSnapshotForEachDescendant(snapshots, snapshot,
> virDomainSnapshotObjListCount,
> &data);
> - else
> + else if (data.flags)
> virDomainSnapshotForEachChild(snapshots, snapshot,
> virDomainSnapshotObjListCount, &data);
> + else
> + data.count = snapshot->nchildren;
>
> return data.count;
> }
> @@ -12271,97 +12296,23 @@ void virDomainSnapshotObjListRemove(virDomainSnapshotObjListPtr snapshots,
> virHashRemoveEntry(snapshots->objs, snapshot->def->name);
> }
>
> -struct snapshot_act_on_child {
> - char *parent;
> - int number;
> - virHashIterator iter;
> - void *data;
> -};
> -
> -static void
> -virDomainSnapshotActOnChild(void *payload,
> - const void *name,
> - void *data)
> -{
> - virDomainSnapshotObjPtr obj = payload;
> - struct snapshot_act_on_child *curr = data;
> -
> - if (obj->def->parent && STREQ(curr->parent, obj->def->parent)) {
> - curr->number++;
> - if (curr->iter)
> - (curr->iter)(payload, name, curr->data);
> - }
> -}
> -
> /* Run iter(data) on all direct children of snapshot, while ignoring all
> * other entries in snapshots. Return the number of children
> * visited. No particular ordering is guaranteed. */
> int
> -virDomainSnapshotForEachChild(virDomainSnapshotObjListPtr snapshots,
> +virDomainSnapshotForEachChild(virDomainSnapshotObjListPtr snapshots ATTRIBUTE_UNUSED,
> virDomainSnapshotObjPtr snapshot,
> virHashIterator iter,
> void *data)
> {
> - struct snapshot_act_on_child act;
> + virDomainSnapshotObjPtr child = snapshot->first_child;
>
> - act.parent = snapshot->def->name;
> - act.number = 0;
> - act.iter = iter;
> - act.data = data;
> - virHashForEach(snapshots->objs, virDomainSnapshotActOnChild, &act);
> -
> - return act.number;
> -}
> -typedef enum {
> - MARK_NONE, /* No relation determined yet */
> - MARK_DESCENDANT, /* Descendant of target */
> - MARK_OTHER, /* Not a descendant of target */
> -} snapshot_mark;
> -
> -struct snapshot_mark_descendant {
> - const char *name; /* Parent's name on round 1, NULL on other rounds. */
> - virDomainSnapshotObjListPtr snapshots;
> - bool marked; /* True if descendants were found in this round */
> -};
> -
> -/* To be called in a loop until no more descendants are found.
> - * Additionally marking known unrelated snapshots reduces the number
> - * of total hash searches needed. */
> -static void
> -virDomainSnapshotMarkDescendant(void *payload,
> - const void *name ATTRIBUTE_UNUSED,
> - void *data)
> -{
> - virDomainSnapshotObjPtr obj = payload;
> - struct snapshot_mark_descendant *curr = data;
> - virDomainSnapshotObjPtr parent = NULL;
> -
> - /* Learned on a previous pass. */
> - if (obj->mark)
> - return;
> -
> - if (curr->name) {
> - /* First round can only find root nodes and direct children. */
> - if (!obj->def->parent) {
> - obj->mark = MARK_OTHER;
> - } else if (STREQ(obj->def->parent, curr->name)) {
> - obj->mark = MARK_DESCENDANT;
> - curr->marked = true;
> - }
> - } else {
> - /* All remaining rounds propagate marks from parents to children. */
> - parent = virDomainSnapshotFindByName(curr->snapshots, obj->def->parent);
> - if (!parent) {
> - VIR_WARN("snapshot hash table is inconsistent!");
> - obj->mark = MARK_OTHER;
> - return;
> - }
> - if (parent->mark) {
> - obj->mark = parent->mark;
> - if (obj->mark == MARK_DESCENDANT)
> - curr->marked = true;
> - }
> + while (child) {
> + (iter)(child, child->def->name, data);
> + child = child->sibling;
> }
> +
> + return snapshot->nchildren;
> }
>
> struct snapshot_act_on_descendant {
> @@ -12378,40 +12329,27 @@ virDomainSnapshotActOnDescendant(void *payload,
> virDomainSnapshotObjPtr obj = payload;
> struct snapshot_act_on_descendant *curr = data;
>
> - if (obj->mark == MARK_DESCENDANT) {
> - curr->number++;
> - (curr->iter)(payload, name, curr->data);
> - }
> - obj->mark = MARK_NONE;
> + curr->number++;
> + (curr->iter)(payload, name, curr->data);
> + virDomainSnapshotForEachDescendant(NULL, obj, curr->iter, curr->data);
> }
>
> /* Run iter(data) on all descendants of snapshot, while ignoring all
> * other entries in snapshots. Return the number of descendants
> * visited. No particular ordering is guaranteed. */
> int
> -virDomainSnapshotForEachDescendant(virDomainSnapshotObjListPtr snapshots,
> +virDomainSnapshotForEachDescendant(virDomainSnapshotObjListPtr snapshots ATTRIBUTE_UNUSED,
> virDomainSnapshotObjPtr snapshot,
> virHashIterator iter,
> void *data)
> {
> - struct snapshot_mark_descendant mark;
> struct snapshot_act_on_descendant act;
>
> - /* virHashForEach does not support nested traversal, so we must
> - * instead iterate until no more snapshots get marked. We
> - * guarantee that on exit, all marks have been cleared again. */
> - mark.name = snapshot->def->name;
> - mark.snapshots = snapshots;
> - mark.marked = true;
> - while (mark.marked) {
> - mark.marked = false;
> - virHashForEach(snapshots->objs, virDomainSnapshotMarkDescendant, &mark);
> - mark.name = NULL;
> - }
> act.number = 0;
> act.iter = iter;
> act.data = data;
> - virHashForEach(snapshots->objs, virDomainSnapshotActOnDescendant, &act);
> + virDomainSnapshotForEachChild(NULL, snapshot,
> + virDomainSnapshotActOnDescendant, &act);
>
> return act.number;
> }
ACK,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list