mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-11 12:46:49 +00:00
perf(storages): a pool's volumes are read with one libvirt call each
wvmStorage.update_volumes looked each volume up by name three times, read its info twice and its XML once: six round trips per volume to the host. It now lists the pool's volumes as objects (listAllVolumes) and reads each one's XML only (volume_details): name, capacity, allocation and format are all in it, and libvirt refreshes a volume for its XML as it does for info(). A pool of N volumes takes 2 + N calls instead of 2 + 6N; 100 volumes over SSH on a test host read in about 110 ms instead of 720 ms, with the same values. - A volume deleted between the listing and its read is left out; any other error is raised. Volumes come sorted by name. - get_volume_details (the API's one volume) reads it the same way. - Only a refused refresh (a clone running in the pool) is tolerated, not any exception. - The pool page reads its volumes and space only to render itself; its actions, which all redirect, no longer read every volume first. - get_volume_size and get_volume_allocation go: nothing else used them.
This commit is contained in:
parent
3aa198304a
commit
befd1747df
3 changed files with 102 additions and 45 deletions
|
|
@ -5,6 +5,20 @@ from vrtManager import util
|
|||
from vrtManager.connection import wvmConnect
|
||||
|
||||
|
||||
def volume_details(vol):
|
||||
"""A volume's name, capacity (size), allocation and format, from its XML:
|
||||
one libvirt call, which refreshes the volume as info() does. Logical and
|
||||
iSCSI volumes have no format (None)."""
|
||||
def read(doc):
|
||||
return {
|
||||
"name": util.get_xpath(doc, "/volume/name"),
|
||||
"size": int(util.get_xpath(doc, "/volume/capacity")),
|
||||
"allocation": int(util.get_xpath(doc, "/volume/allocation")),
|
||||
"type": util.get_xpath(doc, "/volume/target/format/@type"),
|
||||
}
|
||||
return util.get_xml_path(vol.XMLDesc(0), func=read)
|
||||
|
||||
|
||||
class wvmStorages(wvmConnect):
|
||||
def get_storages_info(self):
|
||||
"""Each pool's state, autostart, type, path (an RBD pool's Ceph pool),
|
||||
|
|
@ -255,14 +269,6 @@ class wvmStorage(wvmConnect):
|
|||
def get_volume(self, name):
|
||||
return self.pool.storageVolLookupByName(name)
|
||||
|
||||
def get_volume_size(self, name):
|
||||
vol = self.get_volume(name)
|
||||
return vol.info()[1]
|
||||
|
||||
def get_volume_allocation(self, name):
|
||||
vol = self.get_volume(name)
|
||||
return vol.info()[2]
|
||||
|
||||
def _vol_XMLDesc(self, name):
|
||||
vol = self.get_volume(name)
|
||||
return vol.XMLDesc(0)
|
||||
|
|
@ -286,28 +292,25 @@ class wvmStorage(wvmConnect):
|
|||
return self.pool.refresh(0)
|
||||
|
||||
def get_volume_details(self, volname):
|
||||
with contextlib.suppress(Exception):
|
||||
"""The volume's details (volume_details), the pool refreshed first."""
|
||||
with contextlib.suppress(libvirt.libvirtError): # refused while a volume is cloned in the pool
|
||||
self.refresh()
|
||||
return {
|
||||
"name": volname,
|
||||
"size": self.get_volume_size(volname),
|
||||
"allocation": self.get_volume_allocation(volname),
|
||||
"type": self.get_volume_format_type(volname),
|
||||
}
|
||||
return volume_details(self.get_volume(volname))
|
||||
|
||||
def update_volumes(self):
|
||||
with contextlib.suppress(Exception):
|
||||
"""Every volume's details (volume_details) by name, the pool refreshed
|
||||
first: two calls and one per volume, where a lookup, info() and the
|
||||
XML of each took six. A volume deleted meanwhile is left out."""
|
||||
with contextlib.suppress(libvirt.libvirtError): # refused while a volume is cloned in the pool
|
||||
self.refresh()
|
||||
vols = self.get_volumes()
|
||||
return [
|
||||
{
|
||||
"name": volname,
|
||||
"size": self.get_volume_size(volname),
|
||||
"allocation": self.get_volume_allocation(volname),
|
||||
"type": self.get_volume_format_type(volname),
|
||||
}
|
||||
for volname in vols
|
||||
]
|
||||
volumes = []
|
||||
for vol in self.pool.listAllVolumes(0):
|
||||
try:
|
||||
volumes.append(volume_details(vol))
|
||||
except libvirt.libvirtError as err:
|
||||
if err.get_error_code() != libvirt.VIR_ERR_NO_STORAGE_VOL:
|
||||
raise
|
||||
return sorted(volumes, key=lambda volume: volume["name"])
|
||||
|
||||
def create_volume(
|
||||
self,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue