mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
perf(instances): the VM page reads each kind of domain XML once
The VM page's getters read the domain XML on their own: one load made 86 libvirt calls for a real VM, 29 of them for the same three XML documents (live, live with secrets, persistent) and 6 for the host capabilities. Each call is a round trip to the host. wvmInstance.cached_reads() is a block in which _XMLDesc (per flags value) and get_cap_xml are read from libvirt once; it ends with the block, even on an error, does not nest, and _defineXML drops it. Outside a block every read goes to libvirt as before. Only the VM page view, which does not change the VM, uses it, around its rendering. Views that change the VM keep reading fresh XML: most changes (devices, QoS, memory) do not go through _defineXML, and several views read, change and define more than once in one request. Measured on the test host: 86 -> 55 calls (XMLDesc 29 -> 3, getCapabilities 6 -> 1) for one VM, 82 -> 54 for another; the page took 0.23-0.25 s before, 0.14-0.15 s after. The HTML of both pages is identical before and after (CSRF tokens aside). A test renders the page on libvirt's test driver through the real getters: 25 XML reads before, one per kind now.
This commit is contained in:
parent
2295673203
commit
f5276655fd
4 changed files with 223 additions and 1 deletions
|
|
@ -186,6 +186,9 @@ class wvmInstances(wvmConnect):
|
|||
|
||||
|
||||
class wvmInstance(wvmConnect):
|
||||
# set by cached_reads(): libvirt answers reused within the block
|
||||
_read_cache = None
|
||||
|
||||
def __init__(self, host, login, passwd, conn, vname, uuid=None):
|
||||
wvmConnect.__init__(self, host, login, passwd, conn)
|
||||
self._ip_cache = None
|
||||
|
|
@ -249,12 +252,45 @@ class wvmInstance(wvmConnect):
|
|||
def delete(self, flags=0):
|
||||
self.instance.undefineFlags(flags)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def cached_reads(self):
|
||||
"""
|
||||
Within the block the domain XML (per flags value) and the host
|
||||
capabilities are read from libvirt once, for pages that only read: a
|
||||
VM page reads the XML in some 30 getters. Code that changes the VM
|
||||
must not run inside: most changes (devices, QoS, memory) do not go
|
||||
through _defineXML, the only call that drops the cache.
|
||||
"""
|
||||
if self._read_cache is not None:
|
||||
raise RuntimeError("cached_reads blocks do not nest")
|
||||
self._read_cache = {}
|
||||
try:
|
||||
yield self
|
||||
finally:
|
||||
self._read_cache = None
|
||||
|
||||
def _XMLDesc(self, flag):
|
||||
return self.instance.XMLDesc(flag)
|
||||
cache = self._read_cache
|
||||
if cache is None:
|
||||
return self.instance.XMLDesc(flag)
|
||||
key = ("xml", flag)
|
||||
if key not in cache:
|
||||
cache[key] = self.instance.XMLDesc(flag)
|
||||
return cache[key]
|
||||
|
||||
def _defineXML(self, xml):
|
||||
if self._read_cache is not None:
|
||||
self._read_cache.clear()
|
||||
return self.wvm.defineXML(xml)
|
||||
|
||||
def get_cap_xml(self):
|
||||
cache = self._read_cache
|
||||
if cache is None:
|
||||
return super().get_cap_xml()
|
||||
if "capabilities" not in cache:
|
||||
cache["capabilities"] = super().get_cap_xml()
|
||||
return cache["capabilities"]
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
VIR_DOMAIN_NOSTATE = 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue