ia64/xen-unstable
changeset 16268:09d8b6eb3131
xend: Reduce xenstore transactions when listing domains
In summary, this allows a xenstore transaction object to be passed
around the various device controllers, so that they don't have to do
lots of singleton 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.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
In summary, this allows a xenstore transaction object to be passed
around the various device controllers, so that they don't have to do
lots of singleton 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.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author | Keir Fraser <keir@xensource.com> |
---|---|
date | Tue Oct 30 09:19:43 2007 +0000 (2007-10-30) |
parents | 4034317507de |
children | d25ab83a89e3 |
files | tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/ConsoleController.py tools/python/xen/xend/server/DevController.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/server/pciif.py tools/python/xen/xend/server/tpmif.py tools/python/xen/xend/server/vfbif.py |
line diff
1.1 --- a/tools/python/xen/xend/XendConfig.py Mon Oct 29 16:49:02 2007 +0000 1.2 +++ b/tools/python/xen/xend/XendConfig.py Tue Oct 30 09:19:43 2007 +0000 1.3 @@ -28,6 +28,7 @@ from xen.xend.XendError import VmError 1.4 from xen.xend.XendDevices import XendDevices 1.5 from xen.xend.PrettyPrint import prettyprintstring 1.6 from xen.xend.XendConstants import DOM_STATE_HALTED 1.7 +from xen.xend.xenstore.xstransact import xstransact 1.8 from xen.xend.server.BlktapController import blktap_disk_types 1.9 from xen.xend.server.netif import randomMAC 1.10 from xen.util.blkif import blkdev_name_to_number 1.11 @@ -941,36 +942,43 @@ class XendConfig(dict): 1.12 1.13 # Marshall devices (running or from configuration) 1.14 if not ignore_devices: 1.15 - for cls in XendDevices.valid_devices(): 1.16 - found = False 1.17 + txn = xstransact() 1.18 + try: 1.19 + for cls in XendDevices.valid_devices(): 1.20 + found = False 1.21 1.22 - # figure if there is a dev controller is valid and running 1.23 - if domain and domain.getDomid() != None: 1.24 - try: 1.25 - controller = domain.getDeviceController(cls) 1.26 - configs = controller.configurations() 1.27 - for config in configs: 1.28 - if sxp.name(config) in ('vbd', 'tap'): 1.29 - # The bootable flag is never written to the 1.30 - # store as part of the device config. 1.31 - dev_uuid = sxp.child_value(config, 'uuid') 1.32 - dev_type, dev_cfg = self['devices'][dev_uuid] 1.33 - is_bootable = dev_cfg.get('bootable', 0) 1.34 - config.append(['bootable', int(is_bootable)]) 1.35 + # figure if there is a dev controller is valid and running 1.36 + if domain and domain.getDomid() != None: 1.37 + try: 1.38 + controller = domain.getDeviceController(cls) 1.39 + configs = controller.configurations(txn) 1.40 + for config in configs: 1.41 + if sxp.name(config) in ('vbd', 'tap'): 1.42 + # The bootable flag is never written to the 1.43 + # store as part of the device config. 1.44 + dev_uuid = sxp.child_value(config, 'uuid') 1.45 + dev_type, dev_cfg = self['devices'][dev_uuid] 1.46 + is_bootable = dev_cfg.get('bootable', 0) 1.47 + config.append(['bootable', int(is_bootable)]) 1.48 + 1.49 + sxpr.append(['device', config]) 1.50 1.51 - sxpr.append(['device', config]) 1.52 - 1.53 - found = True 1.54 - except: 1.55 - log.exception("dumping sxp from device controllers") 1.56 - pass 1.57 + found = True 1.58 + except: 1.59 + log.exception("dumping sxp from device controllers") 1.60 + pass 1.61 1.62 - # if we didn't find that device, check the existing config 1.63 - # for a device in the same class 1.64 - if not found: 1.65 - for dev_type, dev_info in self.all_devices_sxpr(): 1.66 - if dev_type == cls: 1.67 - sxpr.append(['device', dev_info]) 1.68 + # if we didn't find that device, check the existing config 1.69 + # for a device in the same class 1.70 + if not found: 1.71 + for dev_type, dev_info in self.all_devices_sxpr(): 1.72 + if dev_type == cls: 1.73 + sxpr.append(['device', dev_info]) 1.74 + 1.75 + txn.commit() 1.76 + except: 1.77 + txn.abort() 1.78 + raise 1.79 1.80 return sxpr 1.81
2.1 --- a/tools/python/xen/xend/XendDomain.py Mon Oct 29 16:49:02 2007 +0000 2.2 +++ b/tools/python/xen/xend/XendDomain.py Tue Oct 30 09:19:43 2007 +0000 2.3 @@ -393,13 +393,22 @@ class XendDomain: 2.4 @rtype: None 2.5 """ 2.6 2.7 + txn = xstransact() 2.8 + try: 2.9 + self._refreshTxn(txn, refresh_shutdown) 2.10 + txn.commit() 2.11 + except: 2.12 + txn.abort() 2.13 + raise 2.14 + 2.15 + def _refreshTxn(self, transaction, refresh_shutdown): 2.16 running = self._running_domains() 2.17 # Add domains that are not already tracked but running in Xen, 2.18 # and update domain state for those that are running and tracked. 2.19 for dom in running: 2.20 domid = dom['domid'] 2.21 if domid in self.domains: 2.22 - self.domains[domid].update(dom, refresh_shutdown) 2.23 + self.domains[domid].update(dom, refresh_shutdown, transaction) 2.24 elif domid not in self.domains and dom['dying'] != 1: 2.25 try: 2.26 new_dom = XendDomainInfo.recreate(dom, False)
3.1 --- a/tools/python/xen/xend/XendDomainInfo.py Mon Oct 29 16:49:02 2007 +0000 3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Tue Oct 30 09:19:43 2007 +0000 3.3 @@ -819,12 +819,15 @@ class XendDomainInfo: 3.4 3.5 self._update_consoles() 3.6 3.7 - def _update_consoles(self): 3.8 + def _update_consoles(self, transaction = None): 3.9 if self.domid == None or self.domid == 0: 3.10 return 3.11 3.12 # Update VT100 port if it exists 3.13 - self.console_port = self.readDom('console/port') 3.14 + if transaction is None: 3.15 + self.console_port = self.readDom('console/port') 3.16 + else: 3.17 + self.console_port = self.readDomTxn(transaction, 'console/port') 3.18 if self.console_port is not None: 3.19 serial_consoles = self.info.console_get_all('vt100') 3.20 if not serial_consoles: 3.21 @@ -837,7 +840,10 @@ class XendDomainInfo: 3.22 3.23 3.24 # Update VNC port if it exists and write to xenstore 3.25 - vnc_port = self.readDom('console/vnc-port') 3.26 + if transaction is None: 3.27 + vnc_port = self.readDom('console/vnc-port') 3.28 + else: 3.29 + vnc_port = self.readDomTxn(transaction, 'console/vnc-port') 3.30 if vnc_port is not None: 3.31 for dev_uuid, (dev_type, dev_info) in self.info['devices'].items(): 3.32 if dev_type == 'vfb': 3.33 @@ -872,6 +878,27 @@ class XendDomainInfo: 3.34 def storeVm(self, *args): 3.35 return xstransact.Store(self.vmpath, *args) 3.36 3.37 + 3.38 + def _readVmTxn(self, transaction, *args): 3.39 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.40 + return transaction.read(*paths) 3.41 + 3.42 + def _writeVmTxn(self, transaction, *args): 3.43 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.44 + return transaction.write(*paths) 3.45 + 3.46 + def _removeVmTxn(self, transaction, *args): 3.47 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.48 + return transaction.remove(*paths) 3.49 + 3.50 + def _gatherVmTxn(self, transaction, *args): 3.51 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.52 + return transaction.gather(paths) 3.53 + 3.54 + def storeVmTxn(self, transaction, *args): 3.55 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.56 + return transaction.store(*paths) 3.57 + 3.58 # 3.59 # Function to update xenstore /dom/* 3.60 # 3.61 @@ -891,6 +918,28 @@ class XendDomainInfo: 3.62 def storeDom(self, *args): 3.63 return xstransact.Store(self.dompath, *args) 3.64 3.65 + 3.66 + def readDomTxn(self, transaction, *args): 3.67 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.68 + return transaction.read(*paths) 3.69 + 3.70 + def gatherDomTxn(self, transaction, *args): 3.71 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.72 + return transaction.gather(*paths) 3.73 + 3.74 + def _writeDomTxn(self, transaction, *args): 3.75 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.76 + return transaction.write(*paths) 3.77 + 3.78 + def _removeDomTxn(self, transaction, *args): 3.79 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.80 + return transaction.remove(*paths) 3.81 + 3.82 + def storeDomTxn(self, transaction, *args): 3.83 + paths = map(lambda x: self.vmpath + "/" + x, args) 3.84 + return transaction.store(*paths) 3.85 + 3.86 + 3.87 def _recreateDom(self): 3.88 complete(self.dompath, lambda t: self._recreateDomFunc(t)) 3.89 3.90 @@ -2223,7 +2272,7 @@ class XendDomainInfo: 3.91 (" as domain %s" % str(dom.domid)) or "")) 3.92 3.93 3.94 - def update(self, info = None, refresh = True): 3.95 + def update(self, info = None, refresh = True, transaction = None): 3.96 """Update with info from xc.domain_getinfo(). 3.97 """ 3.98 log.trace("XendDomainInfo.update(%s) on domain %s", info, 3.99 @@ -2246,7 +2295,7 @@ class XendDomainInfo: 3.100 # TODO: we should eventually get rid of old_dom_states 3.101 3.102 self.info.update_config(info) 3.103 - self._update_consoles() 3.104 + self._update_consoles(transaction) 3.105 3.106 if refresh: 3.107 self.refreshShutdown(info)
4.1 --- a/tools/python/xen/xend/server/ConsoleController.py Mon Oct 29 16:49:02 2007 +0000 4.2 +++ b/tools/python/xen/xend/server/ConsoleController.py Tue Oct 30 09:19:43 2007 +0000 4.3 @@ -19,9 +19,12 @@ class ConsoleController(DevController): 4.4 return (self.allocateDeviceID(), back, {}) 4.5 4.6 4.7 - def getDeviceConfiguration(self, devid): 4.8 - result = DevController.getDeviceConfiguration(self, devid) 4.9 - devinfo = self.readBackend(devid, *self.valid_cfg) 4.10 + def getDeviceConfiguration(self, devid, transaction = None): 4.11 + result = DevController.getDeviceConfiguration(self, devid, transaction) 4.12 + if transaction is None: 4.13 + devinfo = self.readBackend(devid, *self.valid_cfg) 4.14 + else: 4.15 + devinfo = self.readBackendTxn(transaction, devid, *self.valid_cfg) 4.16 config = dict(zip(self.valid_cfg, devinfo)) 4.17 config = dict([(key, val) for key, val in config.items() 4.18 if val != None])
5.1 --- a/tools/python/xen/xend/server/DevController.py Mon Oct 29 16:49:02 2007 +0000 5.2 +++ b/tools/python/xen/xend/server/DevController.py Tue Oct 30 09:19:43 2007 +0000 5.3 @@ -239,15 +239,15 @@ class DevController: 5.4 5.5 self.vm._removeVm("device/%s/%d" % (self.deviceClass, dev)) 5.6 5.7 - def configurations(self): 5.8 - return map(self.configuration, self.deviceIDs()) 5.9 + def configurations(self, transaction = None): 5.10 + return map(lambda x: self.configuration(x, transaction), self.deviceIDs(transaction)) 5.11 5.12 5.13 - def configuration(self, devid): 5.14 + def configuration(self, devid, transaction = None): 5.15 """@return an s-expression giving the current configuration of the 5.16 specified device. This would be suitable for giving to {@link 5.17 #createDevice} in order to recreate that device.""" 5.18 - configDict = self.getDeviceConfiguration(devid) 5.19 + configDict = self.getDeviceConfiguration(devid, transaction) 5.20 sxpr = [self.deviceClass] 5.21 for key, val in configDict.items(): 5.22 if isinstance(val, (types.ListType, types.TupleType)): 5.23 @@ -273,13 +273,16 @@ class DevController: 5.24 'id', devid]] 5.25 5.26 5.27 - def getDeviceConfiguration(self, devid): 5.28 + def getDeviceConfiguration(self, devid, transaction = None): 5.29 """Returns the configuration of a device. 5.30 5.31 @note: Similar to L{configuration} except it returns a dict. 5.32 @return: dict 5.33 """ 5.34 - backdomid = xstransact.Read(self.frontendPath(devid), "backend-id") 5.35 + if transaction is None: 5.36 + backdomid = xstransact.Read(self.frontendPath(devid), "backend-id") 5.37 + else: 5.38 + backdomid = transaction.read(self.frontendPath(devid) + "/backend-id") 5.39 if backdomid is None: 5.40 raise VmError("Device %s not connected" % devid) 5.41 5.42 @@ -416,14 +419,28 @@ class DevController: 5.43 else: 5.44 raise VmError("Device %s not connected" % devid) 5.45 5.46 + def readBackendTxn(self, transaction, devid, *args): 5.47 + frontpath = self.frontendPath(devid) 5.48 + backpath = transaction.read(frontpath + "/backend") 5.49 + if backpath: 5.50 + paths = map(lambda x: backpath + "/" + x, args) 5.51 + return transaction.read(*paths) 5.52 + else: 5.53 + raise VmError("Device %s not connected" % devid) 5.54 + 5.55 def readFrontend(self, devid, *args): 5.56 return xstransact.Read(self.frontendPath(devid), *args) 5.57 5.58 + def readFrontendTxn(self, transaction, devid, *args): 5.59 + paths = map(lambda x: self.frontendPath(devid) + "/" + x, args) 5.60 + return transaction.read(*paths) 5.61 + 5.62 def deviceIDs(self, transaction = None): 5.63 """@return The IDs of each of the devices currently configured for 5.64 this instance's deviceClass. 5.65 """ 5.66 fe = self.backendRoot() 5.67 + 5.68 if transaction: 5.69 return map(lambda x: int(x.split('/')[-1]), transaction.list(fe)) 5.70 else:
6.1 --- a/tools/python/xen/xend/server/blkif.py Mon Oct 29 16:49:02 2007 +0000 6.2 +++ b/tools/python/xen/xend/server/blkif.py Tue Oct 30 09:19:43 2007 +0000 6.3 @@ -124,19 +124,26 @@ class BlkifController(DevController): 6.4 (self.deviceClass, devid, config)) 6.5 6.6 6.7 - def getDeviceConfiguration(self, devid): 6.8 + def getDeviceConfiguration(self, devid, transaction = None): 6.9 """Returns the configuration of a device. 6.10 6.11 @note: Similar to L{configuration} except it returns a dict. 6.12 @return: dict 6.13 """ 6.14 - config = DevController.getDeviceConfiguration(self, devid) 6.15 - devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode', 6.16 - 'uuid') 6.17 + config = DevController.getDeviceConfiguration(self, devid, transaction) 6.18 + if transaction is None: 6.19 + devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode', 6.20 + 'uuid') 6.21 + else: 6.22 + devinfo = self.readBackendTxn(transaction, devid, 6.23 + 'dev', 'type', 'params', 'mode', 'uuid') 6.24 dev, typ, params, mode, uuid = devinfo 6.25 6.26 if dev: 6.27 - dev_type = self.readFrontend(devid, 'device-type') 6.28 + if transaction is None: 6.29 + dev_type = self.readFrontend(devid, 'device-type') 6.30 + else: 6.31 + dev_type = self.readFrontendTxn(transaction, devid, 'device-type') 6.32 if dev_type: 6.33 dev += ':' + dev_type 6.34 config['dev'] = dev
7.1 --- a/tools/python/xen/xend/server/netif.py Mon Oct 29 16:49:02 2007 +0000 7.2 +++ b/tools/python/xen/xend/server/netif.py Tue Oct 30 09:19:43 2007 +0000 7.3 @@ -183,17 +183,20 @@ class NetifController(DevController): 7.4 "network device") 7.5 7.6 7.7 - def getDeviceConfiguration(self, devid): 7.8 + def getDeviceConfiguration(self, devid, transaction = None): 7.9 """@see DevController.configuration""" 7.10 7.11 - result = DevController.getDeviceConfiguration(self, devid) 7.12 + result = DevController.getDeviceConfiguration(self, devid, transaction) 7.13 7.14 config_path = "device/%s/%d/" % (self.deviceClass, devid) 7.15 devinfo = () 7.16 for x in ( 'script', 'ip', 'bridge', 'mac', 7.17 'type', 'vifname', 'rate', 'uuid', 'model', 'accel', 7.18 'security_label'): 7.19 - y = self.vm._readVm(config_path + x) 7.20 + if transaction is None: 7.21 + y = self.vm._readVm(config_path + x) 7.22 + else: 7.23 + y = self.vm._readVmTxn(transaction, config_path + x) 7.24 devinfo += (y,) 7.25 (script, ip, bridge, mac, typ, vifname, rate, uuid, 7.26 model, accel, security_label) = devinfo
8.1 --- a/tools/python/xen/xend/server/pciif.py Mon Oct 29 16:49:02 2007 +0000 8.2 +++ b/tools/python/xen/xend/server/pciif.py Tue Oct 30 09:19:43 2007 +0000 8.3 @@ -78,8 +78,8 @@ class PciController(DevController): 8.4 back['uuid'] = config.get('uuid','') 8.5 return (0, back, {}) 8.6 8.7 - def getDeviceConfiguration(self, devid): 8.8 - result = DevController.getDeviceConfiguration(self, devid) 8.9 + def getDeviceConfiguration(self, devid, transaction = None): 8.10 + result = DevController.getDeviceConfiguration(self, devid, transaction) 8.11 num_devs = self.readBackend(devid, 'num_devs') 8.12 pci_devs = [] 8.13
9.1 --- a/tools/python/xen/xend/server/tpmif.py Mon Oct 29 16:49:02 2007 +0000 9.2 +++ b/tools/python/xen/xend/server/tpmif.py Tue Oct 30 09:19:43 2007 +0000 9.3 @@ -75,9 +75,9 @@ class TPMifController(DevController): 9.4 9.5 return (devid, back, front) 9.6 9.7 - def getDeviceConfiguration(self, devid): 9.8 + def getDeviceConfiguration(self, devid, transaction = None): 9.9 """Returns the configuration of a device""" 9.10 - result = DevController.getDeviceConfiguration(self, devid) 9.11 + result = DevController.getDeviceConfiguration(self, devid, transaction) 9.12 9.13 (instance, uuid, type) = \ 9.14 self.readBackend(devid, 'instance',
10.1 --- a/tools/python/xen/xend/server/vfbif.py Mon Oct 29 16:49:02 2007 +0000 10.2 +++ b/tools/python/xen/xend/server/vfbif.py Tue Oct 30 09:19:43 2007 +0000 10.3 @@ -27,10 +27,13 @@ class VfbifController(DevController): 10.4 return (devid, back, {}) 10.5 10.6 10.7 - def getDeviceConfiguration(self, devid): 10.8 - result = DevController.getDeviceConfiguration(self, devid) 10.9 + def getDeviceConfiguration(self, devid, transaction = None): 10.10 + result = DevController.getDeviceConfiguration(self, devid, transaction) 10.11 10.12 - devinfo = self.readBackend(devid, *CONFIG_ENTRIES) 10.13 + if transaction is None: 10.14 + devinfo = self.readBackend(devid, *CONFIG_ENTRIES) 10.15 + else: 10.16 + devinfo = self.readBackendTxn(transaction, devid, *CONFIG_ENTRIES) 10.17 return dict([(CONFIG_ENTRIES[i], devinfo[i]) 10.18 for i in range(len(CONFIG_ENTRIES)) 10.19 if devinfo[i] is not None])