All of lore.kernel.org
 help / color / mirror / Atom feed
* PATCH: Reduce xenstore transactions when listing domains
@ 2007-10-29 19:02 Daniel P. Berrange
  0 siblings, 0 replies; only message in thread
From: Daniel P. Berrange @ 2007-10-29 19:02 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 1405 bytes --]

This is a followup to patches I've posted a couple of times before:

http://lists.xensource.com/archives/html/xen-devel/2006-10/msg00487.html
http://lists.xensource.com/archives/html/xen-devel/2007-04/msg00663.html


In summary, this allows a xenstore transaction object to be passed around
the various device controllers, so that they don't have todo lots of 
singletone transactions. Transactions have very heavy I/O impact from
xenstored so reducing their number is important. 

When running 3 guests, this patch reduces the impact of 'xm list --long'
from 176 transactions, scaling O(n) with guests, to 26 transactions
with O(1) scaling.

I have previously attempted to also address the same issue with 'xm create'
but that's much harder since the device front/back handshake requires that
XenD use a number of small transactions. So i've not changed anything here.

I have now been running this patch in Fedora builds of Xen for many months
with no reported regressions, so I think its stable enough to be merged
now.

  Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

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  -=| 

[-- Attachment #2: xen-xs-transactions.patch --]
[-- Type: text/plain, Size: 20063 bytes --]

diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/blkif.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/blkif.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/blkif.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/blkif.py	2007-10-29 14:21:03.000000000 -0400
@@ -124,19 +124,26 @@ class BlkifController(DevController):
                           (self.deviceClass, devid, config))
 
 
-    def getDeviceConfiguration(self, devid):
+    def getDeviceConfiguration(self, devid, transaction = None):
         """Returns the configuration of a device.
 
         @note: Similar to L{configuration} except it returns a dict.
         @return: dict
         """
-        config = DevController.getDeviceConfiguration(self, devid)
-        devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode',
-                                   'uuid')
+        config = DevController.getDeviceConfiguration(self, devid, transaction)
+        if transaction is None:
+            devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode',
+                                       'uuid')
+        else:
+            devinfo = self.readBackendTxn(transaction, devid,
+                                          'dev', 'type', 'params', 'mode', 'uuid')
         dev, typ, params, mode, uuid = devinfo
         
         if dev:
-            dev_type = self.readFrontend(devid, 'device-type')
+            if transaction is None:
+                dev_type = self.readFrontend(devid, 'device-type')
+            else:
+                dev_type = self.readFrontendTxn(transaction, devid, 'device-type')
             if dev_type:
                 dev += ':' + dev_type
             config['dev'] = dev
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/ConsoleController.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/ConsoleController.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/ConsoleController.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/ConsoleController.py	2007-10-29 14:21:03.000000000 -0400
@@ -19,9 +19,12 @@ class ConsoleController(DevController):
         return (self.allocateDeviceID(), back, {})
 
 
-    def getDeviceConfiguration(self, devid):
-        result = DevController.getDeviceConfiguration(self, devid)
-        devinfo = self.readBackend(devid, *self.valid_cfg)
+    def getDeviceConfiguration(self, devid, transaction = None):
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
+        if transaction is None:
+            devinfo = self.readBackend(devid, *self.valid_cfg)
+        else:
+            devinfo = self.readBackendTxn(transaction, devid, *self.valid_cfg)
         config = dict(zip(self.valid_cfg, devinfo))
         config = dict([(key, val) for key, val in config.items()
                        if val != None])
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/DevController.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/DevController.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/DevController.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/DevController.py	2007-10-29 14:21:03.000000000 -0400
@@ -239,15 +239,15 @@ class DevController:
 
         self.vm._removeVm("device/%s/%d" % (self.deviceClass, dev))
 
-    def configurations(self):
-        return map(self.configuration, self.deviceIDs())
+    def configurations(self, transaction = None):
+        return map(lambda x: self.configuration(x, transaction), self.deviceIDs(transaction))
 
 
-    def configuration(self, devid):
+    def configuration(self, devid, transaction = None):
         """@return an s-expression giving the current configuration of the
         specified device.  This would be suitable for giving to {@link
         #createDevice} in order to recreate that device."""
-        configDict = self.getDeviceConfiguration(devid)
+        configDict = self.getDeviceConfiguration(devid, transaction)
         sxpr = [self.deviceClass]
         for key, val in configDict.items():
             if isinstance(val, (types.ListType, types.TupleType)):
@@ -273,13 +273,16 @@ class DevController:
                                    'id', devid]]
 
 
-    def getDeviceConfiguration(self, devid):
+    def getDeviceConfiguration(self, devid, transaction = None):
         """Returns the configuration of a device.
 
         @note: Similar to L{configuration} except it returns a dict.
         @return: dict
         """
-        backdomid = xstransact.Read(self.frontendPath(devid), "backend-id")
+        if transaction is None:
+            backdomid = xstransact.Read(self.frontendPath(devid), "backend-id")
+        else:
+            backdomid = transaction.read(self.frontendPath(devid) + "/backend-id")
         if backdomid is None:
             raise VmError("Device %s not connected" % devid)
 
@@ -416,14 +419,28 @@ class DevController:
         else:
             raise VmError("Device %s not connected" % devid)
 
+    def readBackendTxn(self, transaction, devid, *args):
+        frontpath = self.frontendPath(devid)
+        backpath = transaction.read(frontpath + "/backend")
+        if backpath:
+            paths = map(lambda x: backpath + "/" + x, args)
+            return transaction.read(*paths)
+        else:
+            raise VmError("Device %s not connected" % devid)
+
     def readFrontend(self, devid, *args):
         return xstransact.Read(self.frontendPath(devid), *args)
 
+    def readFrontendTxn(self, transaction, devid, *args):
+        paths = map(lambda x: self.frontendPath(devid) + "/" + x, args)
+        return transaction.read(*paths)
+
     def deviceIDs(self, transaction = None):
         """@return The IDs of each of the devices currently configured for
         this instance's deviceClass.
         """
         fe = self.backendRoot()
+
         if transaction:
             return map(lambda x: int(x.split('/')[-1]), transaction.list(fe))
         else:
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/netif.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/netif.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/netif.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/netif.py	2007-10-29 14:22:32.000000000 -0400
@@ -183,17 +183,20 @@ class NetifController(DevController):
                               "network device")
 
 
-    def getDeviceConfiguration(self, devid):
+    def getDeviceConfiguration(self, devid, transaction = None):
         """@see DevController.configuration"""
 
-        result = DevController.getDeviceConfiguration(self, devid)
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
 
         config_path = "device/%s/%d/" % (self.deviceClass, devid)
         devinfo = ()
         for x in ( 'script', 'ip', 'bridge', 'mac',
                    'type', 'vifname', 'rate', 'uuid', 'model', 'accel',
                    'security_label'):
-            y = self.vm._readVm(config_path + x)
+            if transaction is None:
+                y = self.vm._readVm(config_path + x)
+            else:
+                y = self.vm._readVmTxn(transaction, config_path + x)
             devinfo += (y,)
         (script, ip, bridge, mac, typ, vifname, rate, uuid,
          model, accel, security_label) = devinfo
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/pciif.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/pciif.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/pciif.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/pciif.py	2007-10-29 14:21:03.000000000 -0400
@@ -78,8 +78,8 @@ class PciController(DevController):
         back['uuid'] = config.get('uuid','')
         return (0, back, {})
 
-    def getDeviceConfiguration(self, devid):
-        result = DevController.getDeviceConfiguration(self, devid)
+    def getDeviceConfiguration(self, devid, transaction = None):
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
         num_devs = self.readBackend(devid, 'num_devs')
         pci_devs = []
         
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/tpmif.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/tpmif.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/tpmif.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/tpmif.py	2007-10-29 14:21:03.000000000 -0400
@@ -75,9 +75,9 @@ class TPMifController(DevController):
 
         return (devid, back, front)
 
-    def getDeviceConfiguration(self, devid):
+    def getDeviceConfiguration(self, devid, transaction = None):
         """Returns the configuration of a device"""
-        result = DevController.getDeviceConfiguration(self, devid)
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
 
         (instance, uuid, type) = \
                            self.readBackend(devid, 'instance',
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/server/vfbif.py xen-unstable.hg-16125.new/tools/python/xen/xend/server/vfbif.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/server/vfbif.py	2007-10-29 14:05:20.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/server/vfbif.py	2007-10-29 14:21:03.000000000 -0400
@@ -27,10 +27,13 @@ class VfbifController(DevController):
         return (devid, back, {})
 
 
-    def getDeviceConfiguration(self, devid):
-        result = DevController.getDeviceConfiguration(self, devid)
+    def getDeviceConfiguration(self, devid, transaction = None):
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
 
-        devinfo = self.readBackend(devid, *CONFIG_ENTRIES)
+        if transaction is None:
+            devinfo = self.readBackend(devid, *CONFIG_ENTRIES)
+        else:
+            devinfo = self.readBackendTxn(transaction, devid, *CONFIG_ENTRIES)
         return dict([(CONFIG_ENTRIES[i], devinfo[i])
                      for i in range(len(CONFIG_ENTRIES))
                      if devinfo[i] is not None])
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/XendConfig.py xen-unstable.hg-16125.new/tools/python/xen/xend/XendConfig.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/XendConfig.py	2007-10-29 14:05:20.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/XendConfig.py	2007-10-29 14:21:36.000000000 -0400
@@ -28,6 +28,7 @@ from xen.xend.XendError import VmError
 from xen.xend.XendDevices import XendDevices
 from xen.xend.PrettyPrint import prettyprintstring
 from xen.xend.XendConstants import DOM_STATE_HALTED
+from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.server.BlktapController import blktap_disk_types
 from xen.xend.server.netif import randomMAC
 from xen.util.blkif import blkdev_name_to_number
@@ -941,36 +942,43 @@ class XendConfig(dict):
 
         # Marshall devices (running or from configuration)
         if not ignore_devices:
-            for cls in XendDevices.valid_devices():
-                found = False
+            txn = xstransact()
+            try:
+                for cls in XendDevices.valid_devices():
+                    found = False
                 
-                # figure if there is a dev controller is valid and running
-                if domain and domain.getDomid() != None:
-                    try:
-                        controller = domain.getDeviceController(cls)
-                        configs = controller.configurations()
-                        for config in configs:
-                            if sxp.name(config) in ('vbd', 'tap'):
-                                # The bootable flag is never written to the
-                                # store as part of the device config.
-                                dev_uuid = sxp.child_value(config, 'uuid')
-                                dev_type, dev_cfg = self['devices'][dev_uuid]
-                                is_bootable = dev_cfg.get('bootable', 0)
-                                config.append(['bootable', int(is_bootable)])
-
-                            sxpr.append(['device', config])
-
-                        found = True
-                    except:
-                        log.exception("dumping sxp from device controllers")
-                        pass
+                    # figure if there is a dev controller is valid and running
+                    if domain and domain.getDomid() != None:
+                        try:
+                            controller = domain.getDeviceController(cls)
+                            configs = controller.configurations(txn)
+                            for config in configs:
+                                if sxp.name(config) in ('vbd', 'tap'):
+                                    # The bootable flag is never written to the
+                                    # store as part of the device config.
+                                    dev_uuid = sxp.child_value(config, 'uuid')
+                                    dev_type, dev_cfg = self['devices'][dev_uuid]
+                                    is_bootable = dev_cfg.get('bootable', 0)
+                                    config.append(['bootable', int(is_bootable)])
+
+                                sxpr.append(['device', config])
+
+                            found = True
+                        except:
+                            log.exception("dumping sxp from device controllers")
+                            pass
                     
-                # if we didn't find that device, check the existing config
-                # for a device in the same class
-                if not found:
-                    for dev_type, dev_info in self.all_devices_sxpr():
-                        if dev_type == cls:
-                            sxpr.append(['device', dev_info])
+                    # if we didn't find that device, check the existing config
+                    # for a device in the same class
+                    if not found:
+                        for dev_type, dev_info in self.all_devices_sxpr():
+                            if dev_type == cls:
+                                sxpr.append(['device', dev_info])
+
+                txn.commit()
+            except:
+                txn.abort()
+                raise
 
         return sxpr    
     
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/XendDomainInfo.py xen-unstable.hg-16125.new/tools/python/xen/xend/XendDomainInfo.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/XendDomainInfo.py	2007-10-29 14:05:20.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/XendDomainInfo.py	2007-10-29 14:21:03.000000000 -0400
@@ -819,12 +819,15 @@ class XendDomainInfo:
 
         self._update_consoles()
 
-    def _update_consoles(self):
+    def _update_consoles(self, transaction = None):
         if self.domid == None or self.domid == 0:
             return
 
         # Update VT100 port if it exists
-        self.console_port = self.readDom('console/port')
+        if transaction is None:
+            self.console_port = self.readDom('console/port')
+        else:
+            self.console_port = self.readDomTxn(transaction, 'console/port')
         if self.console_port is not None:
             serial_consoles = self.info.console_get_all('vt100')
             if not serial_consoles:
@@ -837,7 +840,10 @@ class XendDomainInfo:
                 
 
         # Update VNC port if it exists and write to xenstore
-        vnc_port = self.readDom('console/vnc-port')
+        if transaction is None:
+            vnc_port = self.readDom('console/vnc-port')
+        else:
+            vnc_port = self.readDomTxn(transaction, 'console/vnc-port')
         if vnc_port is not None:
             for dev_uuid, (dev_type, dev_info) in self.info['devices'].items():
                 if dev_type == 'vfb':
@@ -872,6 +878,27 @@ class XendDomainInfo:
     def storeVm(self, *args):
         return xstransact.Store(self.vmpath, *args)
 
+
+    def _readVmTxn(self, transaction,  *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.read(*paths)
+
+    def _writeVmTxn(self, transaction,  *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.write(*paths)
+
+    def _removeVmTxn(self, transaction,  *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.remove(*paths)
+
+    def _gatherVmTxn(self, transaction,  *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.gather(paths)
+
+    def storeVmTxn(self, transaction,  *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.store(*paths)
+
     #
     # Function to update xenstore /dom/*
     #
@@ -891,6 +918,28 @@ class XendDomainInfo:
     def storeDom(self, *args):
         return xstransact.Store(self.dompath, *args)
 
+
+    def readDomTxn(self, transaction, *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.read(*paths)
+
+    def gatherDomTxn(self, transaction, *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.gather(*paths)
+
+    def _writeDomTxn(self, transaction, *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.write(*paths)
+
+    def _removeDomTxn(self, transaction, *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.remove(*paths)
+
+    def storeDomTxn(self, transaction, *args):
+        paths = map(lambda x: self.vmpath + "/" + x, args)
+        return transaction.store(*paths)
+
+
     def _recreateDom(self):
         complete(self.dompath, lambda t: self._recreateDomFunc(t))
 
@@ -2204,7 +2253,7 @@ class XendDomainInfo:
                            (" as domain %s" % str(dom.domid)) or ""))
         
 
-    def update(self, info = None, refresh = True):
+    def update(self, info = None, refresh = True, transaction = None):
         """Update with info from xc.domain_getinfo().
         """
         log.trace("XendDomainInfo.update(%s) on domain %s", info,
@@ -2227,7 +2276,7 @@ class XendDomainInfo:
         # TODO: we should eventually get rid of old_dom_states
 
         self.info.update_config(info)
-        self._update_consoles()
+        self._update_consoles(transaction)
         
         if refresh:
             self.refreshShutdown(info)
diff -rup xen-unstable.hg-16125.orig/tools/python/xen/xend/XendDomain.py xen-unstable.hg-16125.new/tools/python/xen/xend/XendDomain.py
--- xen-unstable.hg-16125.orig/tools/python/xen/xend/XendDomain.py	2007-10-19 09:51:32.000000000 -0400
+++ xen-unstable.hg-16125.new/tools/python/xen/xend/XendDomain.py	2007-10-29 14:21:03.000000000 -0400
@@ -393,13 +393,22 @@ class XendDomain:
         @rtype: None
         """
 
+        txn = xstransact()
+        try:
+            self._refreshTxn(txn, refresh_shutdown)
+            txn.commit()
+        except:
+            txn.abort()
+            raise
+
+    def _refreshTxn(self, transaction, refresh_shutdown):
         running = self._running_domains()
         # Add domains that are not already tracked but running in Xen,
         # and update domain state for those that are running and tracked.
         for dom in running:
             domid = dom['domid']
             if domid in self.domains:
-                self.domains[domid].update(dom, refresh_shutdown)
+                self.domains[domid].update(dom, refresh_shutdown, transaction)
             elif domid not in self.domains and dom['dying'] != 1:
                 try:
                     new_dom = XendDomainInfo.recreate(dom, False)

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-10-29 19:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-29 19:02 PATCH: Reduce xenstore transactions when listing domains Daniel P. Berrange

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.