188 lines
4.6 KiB
Go
188 lines
4.6 KiB
Go
package ticktock
|
||
|
||
import (
|
||
"fmt"
|
||
"time"
|
||
|
||
"gitlink.org.cn/cloudream/common/pkgs/logger"
|
||
"gitlink.org.cn/cloudream/common/utils/reflect2"
|
||
"gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
|
||
clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
|
||
"gitlink.org.cn/cloudream/jcs-pub/common/models/datamap"
|
||
"gitlink.org.cn/cloudream/jcs-pub/common/pkgs/distlock/reqbuilder"
|
||
)
|
||
|
||
const (
|
||
BatchGetPackageDetailCount = 100
|
||
BatchGetObjectDetailCount = 1000
|
||
)
|
||
|
||
type ChangeRedundancy struct {
|
||
}
|
||
|
||
func (j *ChangeRedundancy) Name() string {
|
||
return reflect2.TypeNameOf[ChangeRedundancy]()
|
||
}
|
||
|
||
func (j *ChangeRedundancy) Execute(t *TickTock) {
|
||
log := logger.WithType[ChangeRedundancy]("TickTock")
|
||
startTime := time.Now()
|
||
log.Debugf("job start")
|
||
defer func() {
|
||
log.Debugf("job end, time: %v", time.Since(startTime))
|
||
}()
|
||
|
||
ctx := &changeRedundancyContext{
|
||
ticktock: t,
|
||
allUserSpaces: make(map[clitypes.UserSpaceID]*userSpaceLoadInfo),
|
||
}
|
||
|
||
spaceIDs, err := t.db.UserSpace().GetAllIDs(t.db.DefCtx())
|
||
if err != nil {
|
||
log.Warnf("get user space ids: %v", err)
|
||
return
|
||
}
|
||
|
||
spaces := t.spaceMeta.GetMany(spaceIDs)
|
||
for _, space := range spaces {
|
||
if space == nil {
|
||
continue
|
||
}
|
||
|
||
ctx.allUserSpaces[space.UserSpace.UserSpaceID] = &userSpaceLoadInfo{
|
||
UserSpace: space,
|
||
}
|
||
}
|
||
|
||
lastPkgID := clitypes.PackageID(0)
|
||
for {
|
||
pkgs, err := db.DoTx21(t.db, t.db.Package().BatchGetDetailPaged, lastPkgID, BatchGetPackageDetailCount)
|
||
if err != nil {
|
||
log.Warnf("get package details: %v", err)
|
||
return
|
||
}
|
||
if len(pkgs) == 0 {
|
||
break
|
||
}
|
||
lastPkgID = pkgs[len(pkgs)-1].Package.PackageID
|
||
|
||
for _, p := range pkgs {
|
||
err := j.changeOne(ctx, p)
|
||
if err != nil {
|
||
log.Warnf("change redundancy: %v", err)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
type changeRedundancyContext struct {
|
||
ticktock *TickTock
|
||
allUserSpaces map[clitypes.UserSpaceID]*userSpaceLoadInfo
|
||
mostBlockStgIDs []clitypes.UserSpaceID
|
||
}
|
||
|
||
type userSpaceLoadInfo struct {
|
||
UserSpace *clitypes.UserSpaceDetail
|
||
AccessAmount float64
|
||
}
|
||
|
||
func (j *ChangeRedundancy) changeOne(ctx *changeRedundancyContext, pkg clitypes.PackageDetail) error {
|
||
log := logger.WithType[ChangeRedundancy]("TickTock")
|
||
db2 := ctx.ticktock.db
|
||
|
||
// allUserSpaces是复用的,所以需要先清空
|
||
for _, space := range ctx.allUserSpaces {
|
||
space.AccessAmount = 0
|
||
}
|
||
|
||
pkgAccessStats, err := db2.PackageAccessStat().GetByPackageID(db2.DefCtx(), pkg.Package.PackageID)
|
||
if err != nil {
|
||
return fmt.Errorf("get package access stats: %w", err)
|
||
}
|
||
|
||
for _, stat := range pkgAccessStats {
|
||
info, ok := ctx.allUserSpaces[stat.UserSpaceID]
|
||
if !ok {
|
||
continue
|
||
}
|
||
info.AccessAmount = stat.Amount
|
||
}
|
||
|
||
lastObjID := clitypes.ObjectID(0)
|
||
for {
|
||
objs, err := db.DoTx31(db2, db2.Object().BatchGetDetailsPaged, pkg.Package.PackageID, lastObjID, BatchGetObjectDetailCount)
|
||
if err != nil {
|
||
return fmt.Errorf("get object details: %w", err)
|
||
}
|
||
if len(objs) == 0 {
|
||
break
|
||
}
|
||
lastObjID = objs[len(objs)-1].Object.ObjectID
|
||
|
||
reen := ctx.ticktock.pubLock.BeginReentrant()
|
||
|
||
var allUpdatings []db.UpdatingObjectRedundancy
|
||
var allSysEvts []datamap.SysEventBody
|
||
|
||
ctx.mostBlockStgIDs = j.summaryRepObjectBlockUserSpaces(ctx, objs, 2)
|
||
|
||
var willShrinks []clitypes.ObjectDetail
|
||
|
||
for _, obj := range objs {
|
||
newRed, selectedSpaces := j.chooseRedundancy(ctx, obj)
|
||
// 冗余策略不需要调整,就检查是否需要收缩
|
||
if newRed == nil {
|
||
willShrinks = append(willShrinks, obj)
|
||
continue
|
||
}
|
||
|
||
reqBlder := reqbuilder.NewBuilder()
|
||
for _, space := range selectedSpaces {
|
||
reqBlder.Shard().Buzy(space.UserSpace.UserSpace.UserSpaceID)
|
||
}
|
||
err := reen.Lock(reqBlder.Build())
|
||
if err != nil {
|
||
log.WithField("ObjectID", obj.Object.ObjectID).Warnf("acquire lock: %s", err.Error())
|
||
continue
|
||
}
|
||
|
||
updating, evt, err := j.doChangeRedundancy(ctx, obj, newRed, selectedSpaces)
|
||
if updating != nil {
|
||
allUpdatings = append(allUpdatings, *updating)
|
||
}
|
||
if evt != nil {
|
||
allSysEvts = append(allSysEvts, evt)
|
||
}
|
||
if err != nil {
|
||
log.WithField("ObjectID", obj.Object.ObjectID).Warnf("%s, its redundancy wont be changed", err.Error())
|
||
continue
|
||
}
|
||
}
|
||
|
||
udpatings, sysEvts, err := j.doRedundancyShrink(ctx, pkg, willShrinks, reen)
|
||
if err != nil {
|
||
log.Warnf("redundancy shrink: %s", err.Error())
|
||
} else {
|
||
allUpdatings = append(allUpdatings, udpatings...)
|
||
allSysEvts = append(allSysEvts, sysEvts...)
|
||
}
|
||
|
||
if len(allUpdatings) > 0 {
|
||
err := db.DoTx10(db2, db2.Object().BatchUpdateRedundancy, allUpdatings)
|
||
if err != nil {
|
||
reen.Unlock()
|
||
log.Warnf("update object redundancy: %s", err.Error())
|
||
return err
|
||
}
|
||
}
|
||
reen.Unlock()
|
||
|
||
for _, e := range allSysEvts {
|
||
ctx.ticktock.evtPub.Publish(e)
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|