From 6591a09f02cf7ddb6237a1fd4d723a627fd978d3 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 9 Apr 2020 16:14:42 -0400 Subject: [PATCH] Speed up ScanVGs by only scanning PVs and LVs at most once. Instead of making calls to ScanPVs and ScanLVs when walking the response from ScanVGs, we only do those once. The ScanPV call is very slow if there are a lot of block devices (including lvm block devices). Overall, this results in considerable speedup. | vm | hardware with-change | 1.22 | 1.35 without | 1.74 | 2.99 They're by no means scientific numbers, but it is a considerable win. --- linux/lvm.go | 55 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/linux/lvm.go b/linux/lvm.go index 8829c0d..1df6de8 100644 --- a/linux/lvm.go +++ b/linux/lvm.go @@ -53,6 +53,10 @@ func (ls *linuxLVM) scanVGs(filter disko.VGFilter, scanArgs ...string) (disko.VG return vgs, err } + if len(vgdatum) == 0 { + return vgs, err + } + for _, vgd := range vgdatum { name := vgd.Name vg := disko.VG{ @@ -66,23 +70,52 @@ func (ls *linuxLVM) scanVGs(filter disko.VGFilter, scanArgs ...string) (disko.VG continue } - pvs, err := ls.ScanPVs(func(p disko.PV) bool { return p.VGName == name }) - if err != nil { - return vgs, err - } + vgs[name] = vg + } - lvs, err := ls.scanLVs(func(d disko.LV) bool { return true }, name) - if err != nil { - return vgs, err + if len(vgs) == 0 { + return vgs, nil + } + + fullVgs := disko.VGSet{} + lvSetsByVG := map[string]disko.LVSet{} + pvSetsByVG := map[string]disko.PVSet{} + + lvs, err := ls.scanLVs(func(d disko.LV) bool { return true }) + + if err != nil { + return vgs, err + } + + for _, lv := range lvs { + if _, ok := lvSetsByVG[lv.VGName]; ok { + lvSetsByVG[lv.VGName][lv.Name] = lv + } else { + lvSetsByVG[lv.VGName] = disko.LVSet{lv.Name: lv} } + } - vg.PVs = pvs - vg.Volumes = lvs + pvs, err := ls.scanPVs(func(d disko.PV) bool { return true }) - vgs[name] = vg + if err != nil { + return vgs, err + } + + for _, pv := range pvs { + if _, ok := pvSetsByVG[pv.VGName]; ok { + pvSetsByVG[pv.VGName][pv.Name] = pv + } else { + pvSetsByVG[pv.VGName] = disko.PVSet{pv.Name: pv} + } + } + + for _, vg := range vgs { + vg.PVs = pvSetsByVG[vg.Name] + vg.Volumes = lvSetsByVG[vg.Name] + fullVgs[vg.Name] = vg } - return vgs, nil + return fullVgs, nil } func (ls *linuxLVM) ScanLVs(filter disko.LVFilter) (disko.LVSet, error) {