[Libvir] Scability / performance fix for virDomainLookupByID

Daniel P. Berrange berrange at redhat.com
Fri Jul 7 14:47:59 UTC 2006


Attached is a patch to significantly increase scalability / performance of 
the xenDaemonLookupByID method. The current implementation would get a
list of all domain names from XenD, and then iterate doing a HTTP GET on
/xend/domain/[name] until the domain with match ID was found. THis had
O(n) complexity, with the result that when running on a system with 20
actives domains, 'virsh list' would have O(n^2) complexity needing ~230  
HTTP calls, giving a runtime of ~9 seconds.

The patch is to make the code do a HTTP GET on /xend/domain/[id] which we
just discovered is a valid URL to access. This makes the method call O(1),
and 'virsh list' is now a saner O(n), and completes in ~1 second. While 
still not great performance, this is certainly much better. I think it
ought to be possible to optimize the code still further so that XenD is
avoided altogether for simple commands which can be fullfilled purely
with data available from Hypervisor, but that will need further 
investigation. 

Please review the patch in case I missed any bugs / edge cases

Regards,
Dan.
-- 
|=- 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  -=| 
-------------- next part --------------
diff -ru libvirt/proxy/libvirt_proxy.c libvirt-new/proxy/libvirt_proxy.c
--- libvirt/proxy/libvirt_proxy.c	2006-07-03 07:12:12.000000000 -0400
+++ libvirt-new/proxy/libvirt_proxy.c	2006-07-07 10:36:17.000000000 -0400
@@ -454,33 +454,14 @@
 	    }
 	    break;
 	case VIR_PROXY_LOOKUP_ID: {
-	    char **names;
-	    char **tmp;
-	    int ident, len;
 	    char *name = NULL;
 	    unsigned char uuid[16];
+	    int len;
 
 	    if (req->len != sizeof(virProxyPacket))
 	        goto comm_error;
 
-	    /*
-	     * Xend API forces to collect the full domain list by names, and
-             * then query each of them until the id is found
-	     */
-	    names = xenDaemonListDomainsOld(conn);
-	    tmp = names;
-
-	    if (names != NULL) {
-	       while (*tmp != NULL) {
-		  ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
-		  if (ident == req->data.arg) {
-		     name = *tmp;
-		     break;
-		  }
-		  tmp++;
-	       }
-	    }
-            if (name == NULL) {
+	    if (xenDaemonDomainLookupByID(conn, req->data.arg, &name, uuid) < 0) {
                 req->data.arg = -1;
             } else {
 	        len = strlen(name);
@@ -492,7 +473,8 @@
 		memcpy(&request.extra.str[0], uuid, 16);
 		strcpy(&request.extra.str[16], name);
 	    }
-	    free(names);
+	    if (name)
+	        free(name);
 	    break;
 	}
 	case VIR_PROXY_LOOKUP_UUID: {
diff -ru libvirt/src/xend_internal.c libvirt-new/src/xend_internal.c
--- libvirt/src/xend_internal.c	2006-07-07 09:59:24.000000000 -0400
+++ libvirt-new/src/xend_internal.c	2006-07-07 10:32:07.000000000 -0400
@@ -1082,7 +1082,7 @@
  */
 int
 xenDaemonDomainLookupByName_ids(virConnectPtr xend, const char *domname,
-                    unsigned char *uuid)
+				unsigned char *uuid)
 {
     struct sexpr *root;
     const char *value;
@@ -1119,6 +1119,62 @@
     return (ret);
 }
 
+
+/**
+ * xenDaemonDomainLookupByID:
+ * @xend: A xend instance
+ * @id: The id of the domain
+ * @name: return value for the name if not NULL
+ * @uuid: return value for the UUID if not NULL
+ *
+ * This method looks up the name of a domain based on its id
+ *
+ * Returns the 0 on success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainLookupByID(virConnectPtr xend,
+			  int id,
+			  char **domname,
+			  unsigned char *uuid)
+{
+    const char *name = NULL;
+    char *dst_uuid;
+    struct sexpr *root;
+
+    memset(uuid, 0, 16);
+
+    root = sexpr_get(xend, "/xend/domain/%d?detail=1", id);
+    if (root == NULL)
+      goto error;
+
+    name = sexpr_node(root, "domain/name");
+    if (name == NULL) {
+      virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+                   "domain informations incomplete, missing name");
+      goto error;
+    }
+    if (domname)
+      *domname = strdup(name);
+
+    dst_uuid = (char *)&uuid[0];
+    if (sexpr_uuid(&dst_uuid, root, "domain/uuid") == NULL) {
+      virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+                   "domain informations incomplete, missing uuid");
+      goto error;
+    }
+
+    sexpr_free(root);
+    return (0);
+
+error:
+    sexpr_free(root);
+    if (*domname) {
+      free(*domname);
+      *domname = NULL;
+    }
+    return (-1);
+}
+
 /**
  * xend_get_node:
  * @xend: A xend instance
@@ -2264,33 +2320,13 @@
  */
 static virDomainPtr
 xenDaemonLookupByID(virConnectPtr conn, int id) {
-    char **names;
-    char **tmp;
-    int ident;
     char *name = NULL;
     unsigned char uuid[16];
     virDomainPtr ret;
 
-    /*
-     * Xend API forces to collect the full domain list by names, and then
-     * query each of them until the id is found
-     */
-    names = xenDaemonListDomainsOld(conn);
-    tmp = names;
-
-    if (names != NULL) {
-       while (*tmp != NULL) {
-          ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
-          if (ident == id) {
-             name = strdup(*tmp);
-             break;
-          }
-          tmp++;
-       }
-       free(names);
-    }
-    if (name == NULL)
+    if (xenDaemonDomainLookupByID(conn, id, &name, uuid) < 0) {
         goto error;
+    }
 
     ret = virGetDomain(conn, name, uuid);
     if (ret == NULL) {
@@ -2298,13 +2334,12 @@
         goto error;
     }
     ret->handle = id;
-    if (name != NULL)
-        free(name);
+    free(name);
     return (ret);
 
-error:
+ error:
     if (name != NULL)
-        free(name);
+      free(name);
     return (NULL);
 }
 
diff -ru libvirt/src/xend_internal.h libvirt-new/src/xend_internal.h
--- libvirt/src/xend_internal.h	2006-07-07 08:30:36.000000000 -0400
+++ libvirt-new/src/xend_internal.h	2006-07-07 10:31:18.000000000 -0400
@@ -535,6 +535,20 @@
 
 
 /**
+ * \brief Lookup the name of a domain
+ * \param xend A xend instance
+ * \param id The id of the domain
+ * \param name pointer to store a copy of the name
+ * \param uuid pointer to store a copy of the uuid
+ *
+ * This method looks up the name/uuid of a domain
+ */
+int xenDaemonDomainLookupByID(virConnectPtr xend,
+			      int id,
+			      char **name, unsigned char *uuid);
+
+
+/**
  * \brief Lookup information about the host machine
  * \param xend A xend instance
  * \return node info on success; NULL (with errno) on error


More information about the libvir-list mailing list