[libvirt] [libvirt-glib] [PATCH v4 0/3] Add API to fetch snapshots

Argh, sorry about the earlier version, die last mail didn't get through the smtp server. This patchset replaces the old one and includes gvir_domain_fetch_snapshots_async as well as a version of gvir_domain_fetch_snapshots that works with it. Timm Bäder (3): libvirt-gobject-domain: Add _fetch_snapshots libvirt-gobject-domain: Add _get_snapshots GVirDomain: Add async version of _fetch_snapshots libvirt-gobject/libvirt-gobject-domain.c | 164 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 51 ++++++++++ libvirt-gobject/libvirt-gobject.sym | 5 + 3 files changed, 220 insertions(+) -- 2.0.1

This function can be used to fetch the snapshots of a domain (according to the given GVirDomainSnapshotListFlags) and save them in a domain-internal GHashTable. A function to access them from outside will be added in a later patch. --- libvirt-gobject/libvirt-gobject-domain.c | 83 ++++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 37 ++++++++++++++ libvirt-gobject/libvirt-gobject.sym | 2 + 3 files changed, 122 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index c6e30e5..180a206 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -38,6 +38,8 @@ struct _GVirDomainPrivate { virDomainPtr handle; gchar uuid[VIR_UUID_STRING_BUFLEN]; + GHashTable *snapshots; + GMutex *lock; }; G_DEFINE_TYPE(GVirDomain, gvir_domain, G_TYPE_OBJECT); @@ -121,6 +123,11 @@ static void gvir_domain_finalize(GObject *object) g_debug("Finalize GVirDomain=%p", domain); + if (priv->snapshots) { + g_hash_table_unref(priv->snapshots); + } + g_mutex_free(priv->lock); + virDomainFree(priv->handle); G_OBJECT_CLASS(gvir_domain_parent_class)->finalize(object); @@ -237,6 +244,7 @@ static void gvir_domain_init(GVirDomain *domain) g_debug("Init GVirDomain=%p", domain); domain->priv = GVIR_DOMAIN_GET_PRIVATE(domain); + domain->priv->lock = g_mutex_new(); } typedef struct virDomain GVirDomainHandle; @@ -1514,3 +1522,78 @@ gvir_domain_create_snapshot(GVirDomain *dom, g_free(custom_xml); return dom_snapshot; } + + + +/** + * gvir_domain_fetch_snapshots: + * @dom: The domain + * @list_flags: bitwise-OR of #GVirDomainSnapshotListFlags + * @cancellable: (allow-none)(transfer-none): cancellation object + * @error: (allow-none): Place-holder for error or NULL + * + * Returns: TRUE on success, FALSE otherwise. + */ +gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GError **error) +{ + GVirDomainPrivate *priv; + virDomainSnapshotPtr *snapshots = NULL; + GVirDomainSnapshot *snap; + GHashTable *snap_table; + int n_snaps = 0; + int i; + gboolean ret = TRUE; + + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE); + g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE); + + priv = dom->priv; + + snap_table = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + + n_snaps = virDomainListAllSnapshots(priv->handle, &snapshots, list_flags); + + if (g_cancellable_set_error_if_cancelled(cancellable, error)) { + ret = FALSE; + goto cleanup; + } + + if (n_snaps < 0) { + gvir_set_error(error, GVIR_DOMAIN_ERROR, 0, + "Unable to fetch snapshots of %s", + gvir_domain_get_name(dom)); + ret = FALSE; + goto cleanup; + } + + for (i = 0; i < n_snaps; i ++) { + if (g_cancellable_set_error_if_cancelled(cancellable, error)) { + ret = FALSE; + goto cleanup; + } + snap = GVIR_DOMAIN_SNAPSHOT(g_object_new(GVIR_TYPE_DOMAIN_SNAPSHOT, + "handle", snapshots[i], + NULL)); + g_hash_table_insert(snap_table, + (gpointer)gvir_domain_snapshot_get_name(snap), + snap); + } + + + g_mutex_lock(priv->lock); + if (priv->snapshots != NULL) + g_hash_table_unref(priv->snapshots); + priv->snapshots = snap_table; + g_mutex_unlock(priv->lock); + +cleanup: + free(snapshots); + return ret; +} diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h index 38d3458..8c1a8e5 100644 --- a/libvirt-gobject/libvirt-gobject-domain.h +++ b/libvirt-gobject/libvirt-gobject-domain.h @@ -183,6 +183,39 @@ typedef enum { GVIR_DOMAIN_REBOOT_GUEST_AGENT = VIR_DOMAIN_REBOOT_GUEST_AGENT, } GVirDomainRebootFlags; +/** + * GVirDomainSnapshotListFlags: + * @GVIR_DOMAIN_SNAPSHOT_LIST_ALL: List all snapshots + * @GVIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS: List all descendants, not just + * children, when listing a snapshot. + * For historical reasons, groups do not use contiguous bits. + * @GVIR_DOMAIN_SNAPSHOT_LIST_ROOTS: Filter by snapshots with no parents, when listing a domain + * @GVIR_DOMAIN_SNAPSHOT_LIST_METADATA: Filter by snapshots which have metadata + * @GVIR_DOMAIN_SNAPSHOT_LIST_LEAVES: Filter by snapshots with no children + * @GVIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES: Filter by snapshots that have children + * @GVIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA: Filter by snapshots with no metadata + * @GVIR_DOMAIN_SNAPSHOT_LIST_INACTIVE: Filter by snapshots taken while guest was shut off + * @GVIR_DOMAIN_SNAPSHOT_LIST_ACTIVE: Filter by snapshots taken while guest was active, and with memory state + * @GVIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY: Filter by snapshots taken while guest was active, but without memory state + * @GVIR_DOMAIN_SNAPSHOT_LIST_INTERNAL: Filter by snapshots stored internal to disk images + * @GVIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL: Filter by snapshots that use files external to disk images + */ +typedef enum { + GVIR_DOMAIN_SNAPSHOT_LIST_ALL = 0, + GVIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS = VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS, + GVIR_DOMAIN_SNAPSHOT_LIST_ROOTS = VIR_DOMAIN_SNAPSHOT_LIST_ROOTS, + GVIR_DOMAIN_SNAPSHOT_LIST_METADATA = VIR_DOMAIN_SNAPSHOT_LIST_METADATA, + GVIR_DOMAIN_SNAPSHOT_LIST_LEAVES = VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, + GVIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES = VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, + GVIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA = VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, + GVIR_DOMAIN_SNAPSHOT_LIST_INACTIVE = VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE, + GVIR_DOMAIN_SNAPSHOT_LIST_ACTIVE = VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, + GVIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY = VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY, + GVIR_DOMAIN_SNAPSHOT_LIST_INTERNAL = VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL, + GVIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL = VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL +} GVirDomainSnapshotListFlags; + + typedef struct _GVirDomainInfo GVirDomainInfo; struct _GVirDomainInfo { @@ -330,6 +363,10 @@ gvir_domain_create_snapshot(GVirDomain *dom, guint flags, GError **err); +gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GError **error); G_END_DECLS #endif /* __LIBVIRT_GOBJECT_DOMAIN_H__ */ diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index b781cc6..781310f 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -236,7 +236,9 @@ LIBVIRT_GOBJECT_0.1.5 { LIBVIRT_GOBJECT_0.1.9 { global: + gvir_domain_fetch_snapshots; gvir_domain_snapshot_delete; + gvir_domain_snapshot_list_flags_get_type; } LIBVIRT_GOBJECT_0.1.5; # .... define new API here using predicted next version number .... -- 2.0.1

On Mon, Jun 30, 2014 at 07:50:14PM +0200, Timm Bäder wrote:
This function can be used to fetch the snapshots of a domain (according to the given GVirDomainSnapshotListFlags) and save them in a domain-internal GHashTable. A function to access them from outside will be added in a later patch. --- libvirt-gobject/libvirt-gobject-domain.c | 83 ++++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 37 ++++++++++++++ libvirt-gobject/libvirt-gobject.sym | 2 + 3 files changed, 122 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index c6e30e5..180a206 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -38,6 +38,8 @@ struct _GVirDomainPrivate { virDomainPtr handle; gchar uuid[VIR_UUID_STRING_BUFLEN]; + GHashTable *snapshots; + GMutex *lock; };
G_DEFINE_TYPE(GVirDomain, gvir_domain, G_TYPE_OBJECT); @@ -121,6 +123,11 @@ static void gvir_domain_finalize(GObject *object)
g_debug("Finalize GVirDomain=%p", domain);
+ if (priv->snapshots) { + g_hash_table_unref(priv->snapshots); + } + g_mutex_free(priv->lock); + virDomainFree(priv->handle);
G_OBJECT_CLASS(gvir_domain_parent_class)->finalize(object); @@ -237,6 +244,7 @@ static void gvir_domain_init(GVirDomain *domain) g_debug("Init GVirDomain=%p", domain);
domain->priv = GVIR_DOMAIN_GET_PRIVATE(domain); + domain->priv->lock = g_mutex_new(); }
typedef struct virDomain GVirDomainHandle; @@ -1514,3 +1522,78 @@ gvir_domain_create_snapshot(GVirDomain *dom, g_free(custom_xml); return dom_snapshot; } + + + +/** + * gvir_domain_fetch_snapshots: + * @dom: The domain + * @list_flags: bitwise-OR of #GVirDomainSnapshotListFlags + * @cancellable: (allow-none)(transfer-none): cancellation object + * @error: (allow-none): Place-holder for error or NULL + * + * Returns: TRUE on success, FALSE otherwise. + */ +gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GError **error) +{ + GVirDomainPrivate *priv; + virDomainSnapshotPtr *snapshots = NULL; + GVirDomainSnapshot *snap; + GHashTable *snap_table; + int n_snaps = 0; + int i; + gboolean ret = TRUE; + + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE); + g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE); + + priv = dom->priv; + + snap_table = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + + n_snaps = virDomainListAllSnapshots(priv->handle, &snapshots, list_flags); + + if (g_cancellable_set_error_if_cancelled(cancellable, error)) { + ret = FALSE; + goto cleanup; + } + + if (n_snaps < 0) { + gvir_set_error(error, GVIR_DOMAIN_ERROR, 0, + "Unable to fetch snapshots of %s", + gvir_domain_get_name(dom)); + ret = FALSE; + goto cleanup; + } + + for (i = 0; i < n_snaps; i ++) { + if (g_cancellable_set_error_if_cancelled(cancellable, error)) { + ret = FALSE; + goto cleanup; + } + snap = GVIR_DOMAIN_SNAPSHOT(g_object_new(GVIR_TYPE_DOMAIN_SNAPSHOT, + "handle", snapshots[i], + NULL)); + g_hash_table_insert(snap_table, + (gpointer)gvir_domain_snapshot_get_name(snap), + snap); + } + + + g_mutex_lock(priv->lock); + if (priv->snapshots != NULL) + g_hash_table_unref(priv->snapshots); + priv->snapshots = snap_table; + g_mutex_unlock(priv->lock); + +cleanup:
This is leaking 'snap_table' in error cases. You can have a if (snap_table != NULL) { g_hash_table_unref (snap_table); } here, and set snap_table to NULL right before the cleanup: label.
+ free(snapshots); + return ret; +} diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h index 38d3458..8c1a8e5 100644 --- a/libvirt-gobject/libvirt-gobject-domain.h +++ b/libvirt-gobject/libvirt-gobject-domain.h @@ -183,6 +183,39 @@ typedef enum { GVIR_DOMAIN_REBOOT_GUEST_AGENT = VIR_DOMAIN_REBOOT_GUEST_AGENT, } GVirDomainRebootFlags;
+/** + * GVirDomainSnapshotListFlags: + * @GVIR_DOMAIN_SNAPSHOT_LIST_ALL: List all snapshots + * @GVIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS: List all descendants, not just + * children, when listing a snapshot. + * For historical reasons, groups do not use contiguous bits. + * @GVIR_DOMAIN_SNAPSHOT_LIST_ROOTS: Filter by snapshots with no parents, when listing a domain + * @GVIR_DOMAIN_SNAPSHOT_LIST_METADATA: Filter by snapshots which have metadata + * @GVIR_DOMAIN_SNAPSHOT_LIST_LEAVES: Filter by snapshots with no children + * @GVIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES: Filter by snapshots that have children + * @GVIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA: Filter by snapshots with no metadata + * @GVIR_DOMAIN_SNAPSHOT_LIST_INACTIVE: Filter by snapshots taken while guest was shut off + * @GVIR_DOMAIN_SNAPSHOT_LIST_ACTIVE: Filter by snapshots taken while guest was active, and with memory state + * @GVIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY: Filter by snapshots taken while guest was active, but without memory state + * @GVIR_DOMAIN_SNAPSHOT_LIST_INTERNAL: Filter by snapshots stored internal to disk images + * @GVIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL: Filter by snapshots that use files external to disk images + */ +typedef enum { + GVIR_DOMAIN_SNAPSHOT_LIST_ALL = 0, + GVIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS = VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS, + GVIR_DOMAIN_SNAPSHOT_LIST_ROOTS = VIR_DOMAIN_SNAPSHOT_LIST_ROOTS, + GVIR_DOMAIN_SNAPSHOT_LIST_METADATA = VIR_DOMAIN_SNAPSHOT_LIST_METADATA, + GVIR_DOMAIN_SNAPSHOT_LIST_LEAVES = VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, + GVIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES = VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES, + GVIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA = VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA, + GVIR_DOMAIN_SNAPSHOT_LIST_INACTIVE = VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE, + GVIR_DOMAIN_SNAPSHOT_LIST_ACTIVE = VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE, + GVIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY = VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY, + GVIR_DOMAIN_SNAPSHOT_LIST_INTERNAL = VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL, + GVIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL = VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL +} GVirDomainSnapshotListFlags; + + typedef struct _GVirDomainInfo GVirDomainInfo; struct _GVirDomainInfo { @@ -330,6 +363,10 @@ gvir_domain_create_snapshot(GVirDomain *dom, guint flags, GError **err);
+gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GError **error); G_END_DECLS
#endif /* __LIBVIRT_GOBJECT_DOMAIN_H__ */ diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index b781cc6..781310f 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -236,7 +236,9 @@ LIBVIRT_GOBJECT_0.1.5 {
LIBVIRT_GOBJECT_0.1.9 { global: + gvir_domain_fetch_snapshots; gvir_domain_snapshot_delete; + gvir_domain_snapshot_list_flags_get_type; } LIBVIRT_GOBJECT_0.1.5;
# .... define new API here using predicted next version number .... -- 2.0.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

... which returns a GList of GVirDomainSnapshots, i.e. without any tree structure or other relationship between the snapshots. --- libvirt-gobject/libvirt-gobject-domain.c | 21 +++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 4 ++++ libvirt-gobject/libvirt-gobject.sym | 1 + 3 files changed, 26 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index 180a206..b12a4a0 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -1597,3 +1597,24 @@ cleanup: free(snapshots); return ret; } + +/** + * gvir_domain_get_snapshots: + * @dom: The domain + * Returns: (element-type LibvirtGObject.DomainSnapshot) (transfer full): A + * list of all the snapshots available for the given domain. The returned + * list should be freed with g_list_free(), after its elements have been + * unreffed with g_object_unref(). + */ +GList *gvir_domain_get_snapshots(GVirDomain *dom) +{ + GList *snapshots = NULL; + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), NULL); + + if (dom->priv->snapshots != NULL) { + snapshots = g_hash_table_get_values(dom->priv->snapshots); + g_list_foreach(snapshots, (GFunc)g_object_ref, NULL); + } + + return snapshots; +} diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h index 8c1a8e5..22870c1 100644 --- a/libvirt-gobject/libvirt-gobject-domain.h +++ b/libvirt-gobject/libvirt-gobject-domain.h @@ -367,6 +367,10 @@ gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, guint list_flags, GCancellable *cancellable, GError **error); + +GList *gvir_domain_get_snapshots(GVirDomain *dom); + + G_END_DECLS #endif /* __LIBVIRT_GOBJECT_DOMAIN_H__ */ diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 781310f..28e547a 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -237,6 +237,7 @@ LIBVIRT_GOBJECT_0.1.5 { LIBVIRT_GOBJECT_0.1.9 { global: gvir_domain_fetch_snapshots; + gvir_domain_get_snapshots; gvir_domain_snapshot_delete; gvir_domain_snapshot_list_flags_get_type; } LIBVIRT_GOBJECT_0.1.5; -- 2.0.1

Hey, On Mon, Jun 30, 2014 at 07:50:15PM +0200, Timm Bäder wrote:
... which returns a GList of GVirDomainSnapshots, i.e. without any tree structure or other relationship between the snapshots.
Looks good, ACK. Any plans to return the snapshots as a tree at some point? Or can the library user reconstruct this tree information from the current API? Christophe

On 07.07, Christophe Fergeau wrote:
Hey,
On Mon, Jun 30, 2014 at 07:50:15PM +0200, Timm Bäder wrote:
... which returns a GList of GVirDomainSnapshots, i.e. without any tree structure or other relationship between the snapshots.
Looks good, ACK. Any plans to return the snapshots as a tree at some point? Or can the library user reconstruct this tree information from the current API?
Christophe
I don't really have plans on this (since I don't need it) but since there's gvir_config_domain_snapshot_get_parent exists I guess it can be done manually (although not very convenient...). Timm

--- libvirt-gobject/libvirt-gobject-domain.c | 60 ++++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 10 ++++++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 72 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index b12a4a0..6b53d25 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -1618,3 +1618,63 @@ GList *gvir_domain_get_snapshots(GVirDomain *dom) return snapshots; } + + + +static void _fetch_snapshots_async_thread(GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { + GError *error = NULL; + gboolean status; + + status = gvir_domain_fetch_snapshots(source_object, + GPOINTER_TO_UINT(task_data), + cancellable, + &error); + if (status) + g_task_return_boolean(task, TRUE); + else + g_task_return_error(task, error); +} + + +/** + * + * @dom: The domain + * @list_flags: bitwise-OR of #GVirDomainSnapshotListFlags + * @cancellable: (allow-none)(transfer-none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_domain_fetch_snapshots_async(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GTask *task; + + g_return_if_fail(GVIR_IS_DOMAIN(dom)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + task = g_task_new(dom, cancellable, callback, user_data); + g_task_set_task_data(task, GUINT_TO_POINTER(list_flags), NULL); + g_task_run_in_thread(task, _fetch_snapshots_async_thread); +} + + +/** + * gvir_domain_fetch_snapshots_finish: + * @dom: a #GVirDomain + * @res: (transfer none): async method result + * + * Returns: TRUE on success, FALSE otherwise. + */ +gboolean gvir_domain_fetch_snapshots_finish(GVirDomain *dom, + GAsyncResult *res, + GError **error) { + g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE); + g_return_val_if_fail(g_task_is_valid(res, dom), FALSE); + + return g_task_propagate_boolean(G_TASK(res), error); +} diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h index 22870c1..9846375 100644 --- a/libvirt-gobject/libvirt-gobject-domain.h +++ b/libvirt-gobject/libvirt-gobject-domain.h @@ -370,6 +370,16 @@ gboolean gvir_domain_fetch_snapshots(GVirDomain *dom, GList *gvir_domain_get_snapshots(GVirDomain *dom); +void gvir_domain_fetch_snapshots_async(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gvir_domain_fetch_snapshots_finish(GVirDomain *dom, + GAsyncResult *res, + GError **error); + G_END_DECLS diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 28e547a..6aa8b86 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -237,6 +237,8 @@ LIBVIRT_GOBJECT_0.1.5 { LIBVIRT_GOBJECT_0.1.9 { global: gvir_domain_fetch_snapshots; + gvir_domain_fetch_snapshots_async; + gvir_domain_fetch_snapshots_finish; gvir_domain_get_snapshots; gvir_domain_snapshot_delete; gvir_domain_snapshot_list_flags_get_type; -- 2.0.1

Hey, On Mon, Jun 30, 2014 at 07:50:16PM +0200, Timm Bäder wrote:
--- libvirt-gobject/libvirt-gobject-domain.c | 60 ++++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 10 ++++++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 72 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index b12a4a0..6b53d25 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -1618,3 +1618,63 @@ GList *gvir_domain_get_snapshots(GVirDomain *dom)
return snapshots; } + + + +static void _fetch_snapshots_async_thread(GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { + GError *error = NULL; + gboolean status; + + status = gvir_domain_fetch_snapshots(source_object, + GPOINTER_TO_UINT(task_data), + cancellable, + &error); + if (status) + g_task_return_boolean(task, TRUE); + else + g_task_return_error(task, error); +} + + +/** + * + * @dom: The domain + * @list_flags: bitwise-OR of #GVirDomainSnapshotListFlags + * @cancellable: (allow-none)(transfer-none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_domain_fetch_snapshots_async(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GTask *task; + + g_return_if_fail(GVIR_IS_DOMAIN(dom)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + task = g_task_new(dom, cancellable, callback, user_data);
GTask was introduced in glib 2.36, so configure.ac needs to be updated to reflect that. glib 2.36 was released in March 2013, and is available in RHEL7, so using this would be fine with me. Others may want to disagree though :)
+ g_task_set_task_data(task, GUINT_TO_POINTER(list_flags), NULL); + g_task_run_in_thread(task, _fetch_snapshots_async_thread);
I'm a bit unclear as how the initial ref obtained through g_task_new() is handled. Have you checked it's correctly freed after _finish() has been called and that it's not leaked? Looks good otherwise. Christophe

On Mon, Jul 07, 2014 at 12:55:33PM +0200, Christophe Fergeau wrote:
GTask was introduced in glib 2.36, so configure.ac needs to be updated to reflect that.
Forgot to add here that the minimum glib requirement is also listed in libvirt-glib.spec.in. Ideally, this should be changed to be automatically substituted from whatever is listed in configure.ac. Christophe

On Mon, Jul 07, 2014 at 02:19:39PM +0200, Christophe Fergeau wrote:
Ideally, this should be changed to be automatically substituted from whatever is listed in configure.ac.
https://www.redhat.com/archives/libvir-list/2014-July/msg00315.html does that. Christophe

On 07.07, Christophe Fergeau wrote:
Hey,
On Mon, Jun 30, 2014 at 07:50:16PM +0200, Timm Bäder wrote:
--- libvirt-gobject/libvirt-gobject-domain.c | 60 ++++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-domain.h | 10 ++++++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 72 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c index b12a4a0..6b53d25 100644 --- a/libvirt-gobject/libvirt-gobject-domain.c +++ b/libvirt-gobject/libvirt-gobject-domain.c @@ -1618,3 +1618,63 @@ GList *gvir_domain_get_snapshots(GVirDomain *dom)
return snapshots; } + + + +static void _fetch_snapshots_async_thread(GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) { + GError *error = NULL; + gboolean status; + + status = gvir_domain_fetch_snapshots(source_object, + GPOINTER_TO_UINT(task_data), + cancellable, + &error); + if (status) + g_task_return_boolean(task, TRUE); + else + g_task_return_error(task, error); +} + + +/** + * + * @dom: The domain + * @list_flags: bitwise-OR of #GVirDomainSnapshotListFlags + * @cancellable: (allow-none)(transfer-none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_domain_fetch_snapshots_async(GVirDomain *dom, + guint list_flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GTask *task; + + g_return_if_fail(GVIR_IS_DOMAIN(dom)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + task = g_task_new(dom, cancellable, callback, user_data);
GTask was introduced in glib 2.36, so configure.ac needs to be updated to reflect that. glib 2.36 was released in March 2013, and is available in RHEL7, so using this would be fine with me. Others may want to disagree though :)
+ g_task_set_task_data(task, GUINT_TO_POINTER(list_flags), NULL); + g_task_run_in_thread(task, _fetch_snapshots_async_thread);
I'm a bit unclear as how the initial ref obtained through g_task_new() is handled. Have you checked it's correctly freed after _finish() has been called and that it's not leaked?
Ouch, I've been fooled by the example in the GTask documentation (which was wrong), it does ineed have to be unreffed in the function that calls g_task_run_in_thread (which will itself take its own ref).
Looks good otherwise.
Christophe
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
participants (2)
-
Christophe Fergeau
-
Timm Bäder