A little over a month ago I proposed an API extension for enabling long
operations to be done as asynchronous background jobs.

http://www.redhat.com/archives/libvir-list/2008-January/msg00040.html

While the proof of concept definitely worked, having played around & thought
about it a little more I feel we can do better than that initial proposal.
Some things I didn't like about it:

 - Complicated reference counting. This was because jobs may or may not be 
   tied to a virDomainPtr object depending on whether the job was a creation
   attempt, or an operation on an existing object.
 - Complicated app code because they now had to track both Job & Domain 
   objects together.
 - Added too many new APIs - this was a consequence of needing the separate
   top level virJob object, adding lots of XXXJob variants for APIs.
 - Complicated internal drivers due to the separate Job object.

So to try and address this I've come up with an alternative, simpler design
for this. The key idea is to get rid of the top level 'Job' object and make
use of the 'flags' field present in (almost) all the APIs which need to have
async behaviour.

First of all, for the couple of APIs which don't have 'flags' we add new
variants taking a 'flags' parameter.

For each API needing to allow async operation, we define a flag for this
eg, 

   virDomainCreateXML  -> VIR_DOMAIN_CREATE_XML_ASYNC
   virDomainRestore    -> VIR_DOMAIN_RESTORE_ASYNC
   virStoragePoolBuild -> VIR_STORAGE_POOL_BUILD_ASYNC

If the flag is omitted, current semantics are unchanged, so existing apps
are not impacted.

If you pass the appropriate XXX_ASYNC flag, then you cannot assume that
the operation is complete upon returning from the call. To check completion
status you ask for the virJobInfo  data. This can be done with whichever of
these APIs matches:

    virDomainGetJobInfo(virDomainPtr dom, virJobInfoPtr job)
    virStoragePoolGetJobInfo(virStoragePoolPtr vol, virJobInfoPtr job)
    virStorageVolGetJobInfo(virStorageVolPtr vol, virJobInfoPtr job)

Finally, you can cancel an operation:

     virDomainCancelJob(virDomainPtr dom);
     virStoragePoolCancelJob(virStoragePoolPtr pool);
     virStorageVolCancelJob(virStorageVolPtr vol);

If you passed the XXX_ASYNC flag, it is forbidden to call any APIs on the
object other than the  XXXCancelJob() or XXXGetJobInfo()  methods, until
the job is complete.  This was true of the previous proof of concept I did
but I didn't spell it out at the time.

I've not done the intenral driver impl of this proposal yet, but it will
be easier/clearer than the previous impl, and the virsh changes will be
much less intrusive since we're merely passing a flag instead of calling
a completely separate API.

The patch below illustrates the proposed public API - note how its only
adding a handful of new entry points - 3 virDomain methods needed an extra
flags parameter - all the storage APIs were written to take flags already

Dan.

diff -r 3b8d18bc4d3e include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in      Wed Feb 20 12:20:50 2008 -0500
+++ b/include/libvirt/libvirt.h.in      Wed Feb 20 14:14:09 2008 -0500
@@ -408,6 +408,62 @@ char *                  virConnectGetCap
 
 unsigned long long     virNodeGetFreeMemory    (virConnectPtr conn);
 
+
+
+/*
+ * Asynchronous background jobs
+ */
+
+/**
+ * virJobType;
+ *
+ * A job may have a finite bounded progress, or may be
+ * unbounded.
+ */
+typedef enum {
+  VIR_JOB_BOUNDED      = 0, /* finite, 0-> 100 completion */
+  VIR_JOB_UNBOUNDED    = 1, /* unknown completion percent */
+} virJobType;
+
+
+/**
+ * virJobState;
+ *
+ * A job may be in one of several states
+ */
+typedef enum {
+  VIR_JOB_RUNNING = 0,     /* Still active */
+  VIR_JOB_COMPLETE = 1,    /* Completed successfully */
+  VIR_JOB_FAILED = 2,      /* Failed to complete see virJobGetError */
+  VIR_JOB_CANCELLED = 3,   /* User requested cancellation */
+} virJobState;
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfo is a structure filled by virJobGetInfo() and extracting
+ * runtime informations for a given active Job
+ */
+
+typedef struct _virJobInfo virJobInfo;
+
+struct _virJobInfo {
+  int type;                  /* One of virJobType constants */
+  int state;                 /* One of virJobState constants */
+  unsigned int runningTime;  /* Actual running time in seconds */
+  unsigned int remainingTime;/* Estimated remaining time in seconds */
+  int percentComplete;       /* Completion progress 0 -> 100, if 
VIR_JOB_BOUNDED */
+};
+
+/**
+ * virJobInfoPtr:
+ *
+ * a virJobInfoPtr is a pointer to a virJobInfo structure.
+ */
+
+typedef virJobInfo *virJobInfoPtr;
+
+
 /*
  * Gather list of running domains
  */
@@ -447,6 +503,11 @@ int                        virDomainDestroy        
(virDomainPtr dom
 int                    virDomainDestroy        (virDomainPtr domain);
 int                    virDomainFree           (virDomainPtr domain);
 
+
+int                     virDomainGetJobInfo     (virDomainPtr dom,
+                                                virJobInfoPtr info);
+int                     virDomainCancelJob      (virDomainPtr dom);
+
 /*
  * Domain suspend/resume
  */
@@ -458,8 +519,14 @@ int                        virDomainResume         
(virDomainPtr dom
  */
 int                    virDomainSave           (virDomainPtr domain,
                                                 const char *to);
+int                    virDomainSaveFlags      (virDomainPtr domain,
+                                                const char *to,
+                                                unsigned int flags);
 int                    virDomainRestore        (virConnectPtr conn,
                                                 const char *from);
+int                    virDomainRestoreFlags   (virConnectPtr conn,
+                                                const char *from,
+                                                unsigned int flags);
 
 /*
  * Domain core dump
@@ -535,6 +602,8 @@ int                 virConnectListDefinedDomains (virC
                                                 char **const names,
                                                 int maxnames);
 int                    virDomainCreate         (virDomainPtr domain);
+int                    virDomainCreateFlags    (virDomainPtr domain,
+                                                unsigned int flags);
 
 int                    virDomainGetAutostart   (virDomainPtr domain,
                                                 int *autostart);
@@ -897,6 +966,11 @@ int                        virStoragePoolRefresh           
(virStorage
 int                    virStoragePoolRefresh           (virStoragePoolPtr pool,
                                                         unsigned int flags);
 
+int                     virStoragePoolGetJobInfo        (virStoragePoolPtr 
pool,
+                                                        virJobInfoPtr info);
+int                     virStoragePoolCancelJob         (virStoragePoolPtr 
pool);
+
+
 /*
  * StoragePool information
  */
@@ -955,6 +1029,10 @@ char *                    virStorageVolGetXMLDesc         
(virSt
 
 char *                 virStorageVolGetPath            (virStorageVolPtr vol);
 
+int                     virStorageVolGetJobInfo         (virStoragePoolPtr 
pool,
+                                                        virJobInfoPtr info);
+int                     virStorageVolCancelJob          (virStoragePoolPtr 
pool);
+
 #ifdef __cplusplus
 }
 #endif

.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to