[libvirt] [PATCH 1/5] lib: Add public api to enable atomic listing of guest

Eric Blake eblake at redhat.com
Mon May 21 22:42:41 UTC 2012


On 05/20/2012 09:56 AM, Peter Krempa wrote:
> This patch adds a new public api that lists domains. The new approach is
> different from those used before. There are four key points to this:
> 
> 1) The list is acquired atomicaly and contains both active and inactive

s/atomicaly/atomically/

> domains (guests). This eliminates the need to call two different list
> APIs, where the state might change in between of the calls.

Here, you may want to merge in points from my RFC in your v2, such as
the ability to do filtering.

> 
> 2) The returned list consists of virDomainPtrs instead of names or ID's
> that have to be converted to virDomainPtrs anyways using separate calls
> for each one of them. This is more convenient and saves resources and
> application code in most (all?) cases.

I don't know about 'saves resources' - we are actually passing more over
the RPC wire.  But definitely more convenient, and less application code.

> 
> 3) The returned list is auto-allocated. This saves a lot hassle for the
> users.
> 
> 4) The python binding returns a list of domain objects that is very neat
> to work with.
> 
> The only problem with this approach is no support from code generators
> so both RPC code and python bindings had to be written manualy.

s/manualy/manually/

> 
> *include/libvirt/libvirt.h.in: - add API prototype
>                                - clean up whitespace mistakes nearby
> *python/generator.py: - inhibit generation of the bindings for the new
>                         api
> *src/driver.h: - add driver prototype
>                - clean up some whitespace mistakes nearby
> *src/libvirt.c: - add public implementation
> *src/libvirt_public.syms: - export the new symbol
> ---
>  include/libvirt/libvirt.h.in |    8 +++++-
>  python/generator.py          |    1 +
>  src/driver.h                 |   12 ++++++++--
>  src/libvirt.c                |   46 ++++++++++++++++++++++++++++++++++++++++++
>  src/libvirt_public.syms      |    5 ++++
>  5 files changed, 67 insertions(+), 5 deletions(-)
> 
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index a817db8..2dacd45 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -1759,8 +1759,12 @@ int                     virDomainUndefineFlags   (virDomainPtr domain,
>                                                    unsigned int flags);
>  int                     virConnectNumOfDefinedDomains  (virConnectPtr conn);
>  int                     virConnectListDefinedDomains (virConnectPtr conn,
> -                                                 char **const names,
> -                                                 int maxnames);
> +                                                      char **const names,
> +                                                      int maxnames);
> +int                     virConnectListAllDomains (virConnectPtr conn,
> +                                                  virDomainPtr **domains,

Hmm - time for me to think out loud.  Your signature differs from mine.
 I proposed:

virDomainPtr *domains
aka
virDomain **domains

where my return value would be an array of virDomain objects, and the
caller would have to do:

virDomainPtr dom, first;
virConnectListAllDomains(conn, &first, flags);
dom = first;
while (dom) {
   use dom;
   virDomainFree(dom);
   dom++;
}
free(first);

But that would only work if virDomain is not an opaque type.

You proposed:

virDomainPtr **domains
aka
virDomain ***domains

where the return is an array of virDomainPtr pointers.  The caller would
then do:

virDomainPtr *array;
virDomainPtr dom;
int i = 0;
virConnectListAllDomains(conn, &array, flags);
dom = array[0];
do {
   use dom;
   virDomainFree(dom);
   dom = array[i++];
} while (dom);
free(array);

(Of course, you could use a for (i=0; i < ret; i++) loop instead of a
while loop; I chose that style to constrast the difference between the
number of pointer dereferences needed).  In conclusion, I think your
style is right.  But it also means that we ought to document a sample
usage as part of the API call :)

> +                                                  int ndomains,

Drop the ndomains argument.

> +                                                  unsigned int flags);
>  int                     virDomainCreate         (virDomainPtr domain);
>  int                     virDomainCreateWithFlags (virDomainPtr domain,
>                                                   unsigned int flags);
> diff --git a/python/generator.py b/python/generator.py
> index 9530867..a81fe4d 100755
> --- a/python/generator.py
> +++ b/python/generator.py
> @@ -453,6 +453,7 @@ skip_function = (
>      'virConnectDomainEventDeregisterAny', # overridden in virConnect.py
>      'virSaveLastError', # We have our own python error wrapper
>      'virFreeError', # Only needed if we use virSaveLastError
> +    'virConnectListAllDomains', #overriden in virConnect.py

s/overriden/overridden/


> +++ b/src/driver.h
> @@ -251,9 +251,14 @@ typedef char *
>                                             const char *domainXml,
>                                             unsigned int flags);
>  typedef int
> -        (*virDrvListDefinedDomains)	(virConnectPtr conn,
> -                                         char **const names,
> -                                         int maxnames);
> +        (*virDrvListDefinedDomains) (virConnectPtr conn,
> +                                     char **const names,
> +                                     int maxnames);
> +typedef int
> +        (*virDrvConnectListAllDomains) (virConnectPtr conn,
> +                                        virDomainPtr **domains,
> +                                        int ndomains,

Again, drop ndomains.


> @@ -1014,6 +1019,7 @@ struct _virDriver {
>      virDrvDomainGetDiskErrors domainGetDiskErrors;
>      virDrvDomainSetMetadata domainSetMetadata;
>      virDrvDomainGetMetadata domainGetMetadata;
> +    virDrvConnectListAllDomains connectListAllDomains;

Order doesn't matter in this file; so I'd stick it closer to
listDomains/numOfDomains, not here at the end.  Your name is long; my
preliminary code went with the shorter 'listAllDomains'.


> 
>  /**
> + * virConnectListAllDomains:
> + * @conn: Pointer to the hypervisor connection.
> + * @domains: Pointer to a variable to store the array containing domain objects
> + *           or NULL if the list is not required (just returns number of guests).

Nice idea - I hadn't thought of allowing NULL for counting.

> + * @ndomains: Maximum number of requested guests. Set to -1 for no limits.

Drop.

> + * @flags: Not used yet. Callers must pass 0.

See my RFC on how to use this for filtering.

> + *
> + * List all guests (domains). This function allocates and returns a complete list
> + * of guests. Caller has to free the returned virDomainPtrs and the array.

My wording mentioned: virDomainFree() on each guest, then free() on the
array.  Be specific, otherwise someone will do it wrong and leak memory.
 Again, sample code in this API can't hurt.

> + *
> + * Returns number of guests found (and stored in *domains) or -1 on error.
> + */
> +int
> +virConnectListAllDomains(virConnectPtr conn,
> +                         virDomainPtr **domains,
> +                         int ndomains,
> +                         unsigned int flags)
> +{
> +    VIR_DEBUG("conn=%p, domains=%p, ndomains=%d, flags=%x",
> +              conn, domains, ndomains, flags);

Adjust for the loss of ndomains.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120521/620ddcf5/attachment-0001.sig>


More information about the libvir-list mailing list