Merge pull request #16930 from ioito/hotfix/qx-optimized-cachedimage-guest-list

fix(region): optimized guest and cachedimage list speed
This commit is contained in:
Zexi Li
2023-05-05 17:10:32 +08:00
committed by GitHub
5 changed files with 94 additions and 12 deletions
+7 -1
View File
@@ -30,6 +30,12 @@ type CachedImageManagerCacheImageInput struct {
ImageId string `json:"image_id"`
}
type CachedimageUsage struct {
// 此镜像被使用次数
// example: 0
CachedCount int `json:"cached_count"`
}
type CachedimageDetails struct {
apis.SharableVirtualResourceDetails
@@ -56,7 +62,7 @@ type CachedimageDetails struct {
// 此镜像被使用次数
// example: 0
CachedCount int `json:"cached_count"`
CachedimageUsage
}
type CachedImageSetClassMetadataInput struct {
+3
View File
@@ -274,6 +274,9 @@ type HostResourceInfo struct {
// 宿主机序列号
HostSN string `json:"host_sn"`
// 宿主是否启用
HostEnabled bool `json:"host_enabled"`
// 宿主机状态
HostStatus string `json:"host_status"`
+68 -6
View File
@@ -26,6 +26,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/httputils"
"yunion.io/x/pkg/util/rbacscope"
@@ -103,12 +104,16 @@ func (self SCachedimage) GetGlobalId() string {
return self.ExternalId
}
func (self *SCachedimage) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
cnt, err := self.getStoragecacheCount()
if err != nil {
return httperrors.NewInternalServerError("ValidateDeleteCondition error %s", err)
func (self *SCachedimage) ValidateDeleteCondition(ctx context.Context, info *api.CachedimageDetails) error {
if gotypes.IsNil(info) {
info = &api.CachedimageDetails{}
count, err := CachedimageManager.TotalResourceCount([]string{self.Id})
if err != nil {
return err
}
info.CachedimageUsage, _ = count[self.Id]
}
if cnt > 0 {
if info.CachedCount > 0 {
return httperrors.NewNotEmptyError("The image has been cached on storages")
}
if self.GetStatus() == api.CACHED_IMAGE_STATUS_ACTIVE && !self.isReferenceSessionExpire() {
@@ -396,6 +401,54 @@ func (manager *SCachedimageManager) getImageInfo(ctx context.Context, userCred m
return manager.getImageByName(ctx, userCred, imageId, refresh)
}
func (cm *SCachedimageManager) query(manager db.IModelManager, field string, cacheIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
q := manager.Query()
if filter != nil {
q = filter(q)
}
sq := q.SubQuery()
return sq.Query(
sq.Field("cachedimage_id"),
sqlchemy.COUNT(field),
).In("cachedimage_id", cacheIds).GroupBy(sq.Field("cachedimage_id")).SubQuery()
}
type CachedimageUsageCount struct {
Id string
api.CachedimageUsage
}
func (manager *SCachedimageManager) TotalResourceCount(cacheIds []string) (map[string]api.CachedimageUsage, error) {
ret := map[string]api.CachedimageUsage{}
scSQ := manager.query(StoragecachedimageManager, "cached_cnt", cacheIds, nil)
caches := manager.Query().SubQuery()
cachesQ := caches.Query(
sqlchemy.SUM("cached_count", scSQ.Field("cached_cnt")),
)
cachesQ.AppendField(cachesQ.Field("id"))
cachesQ = cachesQ.LeftJoin(scSQ, sqlchemy.Equals(cachesQ.Field("id"), scSQ.Field("cachedimage_id")))
cachesQ = cachesQ.Filter(sqlchemy.In(cachesQ.Field("id"), cacheIds)).GroupBy(cachesQ.Field("id"))
counts := []CachedimageUsageCount{}
err := cachesQ.All(&counts)
if err != nil {
return nil, errors.Wrapf(err, "cachesQ.All")
}
for i := range counts {
ret[counts[i].Id] = counts[i].CachedimageUsage
}
return ret, nil
}
func (manager *SCachedimageManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
@@ -406,6 +459,7 @@ func (manager *SCachedimageManager) FetchCustomizeColumns(
) []api.CachedimageDetails {
rows := make([]api.CachedimageDetails, len(objs))
virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
cacheIds := make([]string, len(objs))
for i := range rows {
ci := objs[i].(*SCachedimage)
rows[i] = api.CachedimageDetails{
@@ -415,7 +469,15 @@ func (manager *SCachedimageManager) FetchCustomizeColumns(
OsVersion: ci.GetOSVersion(),
Hypervisor: ci.GetHypervisor(),
}
rows[i].CachedCount, _ = ci.getStoragecacheCount()
cacheIds[i] = ci.Id
}
usage, err := manager.TotalResourceCount(cacheIds)
if err != nil {
log.Errorf("TotalResourceCount error: %v", err)
return rows
}
for i := range rows {
rows[i].CachedimageUsage, _ = usage[cacheIds[i]]
}
return rows
}
+15 -5
View File
@@ -27,6 +27,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/billing"
"yunion.io/x/pkg/util/compare"
@@ -834,13 +835,22 @@ func (guest *SGuest) ValidatePurgeCondition(ctx context.Context) error {
return guest.validateDeleteCondition(ctx, true)
}
func (guest *SGuest) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
host, _ := guest.GetHost()
if host != nil && guest.GetHypervisor() != api.HYPERVISOR_BAREMETAL {
if !host.GetEnabled() {
func (guest *SGuest) ValidateDeleteCondition(ctx context.Context, info *api.ServerDetails) error {
if gotypes.IsNil(info) {
info = &api.ServerDetails{}
host, err := guest.GetHost()
if err != nil {
return err
}
info.HostType = host.HostType
info.HostEnabled = host.Enabled.Bool()
info.HostStatus = host.HostStatus
}
if len(info.HostType) > 0 && guest.GetHypervisor() != api.HYPERVISOR_BAREMETAL {
if !info.HostEnabled {
return httperrors.NewInputParameterError("Cannot delete server on disabled host")
}
if host.HostStatus != api.HOST_ONLINE {
if info.HostStatus != api.HOST_ONLINE {
return httperrors.NewInputParameterError("Cannot delete server on offline host")
}
}
+1
View File
@@ -105,6 +105,7 @@ func (manager *SHostResourceBaseManager) FetchCustomizeColumns(
rows[i].Host = host.Name
rows[i].HostSN = host.SN
rows[i].HostStatus = host.Status
rows[i].HostEnabled = host.Enabled.Bool()
rows[i].HostServiceStatus = host.HostStatus
rows[i].HostType = host.HostType
rows[i].ManagerId = host.ManagerId