package ticktock import ( "fmt" "time" "github.com/samber/lo" "gitlink.org.cn/cloudream/common/pkgs/logger" "gitlink.org.cn/cloudream/common/pkgs/mq" "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" stgglb "gitlink.org.cn/cloudream/jcs-pub/common/globals" hubmq "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/mq/hub" ) // CheckShardStore 代表一个用于处理代理缓存检查事件的结构体 type CheckShardStore struct { } func (j *CheckShardStore) Name() string { return reflect2.TypeNameOf[CheckShardStore]() } // Execute 执行缓存检查操作,对比本地缓存与代理返回的缓存信息,更新数据库中的缓存记录 func (j *CheckShardStore) Execute(t *TickTock) { log := logger.WithType[CheckShardStore]("TickTock") startTime := time.Now() log.Debugf("job start") defer func() { log.Debugf("job end, time: %v", time.Since(startTime)) }() db2 := t.db spaceIDs, err := db2.UserSpace().GetAllIDs(db2.DefCtx()) if err != nil { log.Warnf("getting all user space ids: %s", err.Error()) return } for _, spaceID := range spaceIDs { detail := t.spaceMeta.Get(spaceID) if detail == nil { continue } err := j.checkOne(t, detail) if err != nil { log.Warnf("checking user space %v: %v", detail.String(), err) continue } } } func (j *CheckShardStore) checkOne(t *TickTock, space *clitypes.UserSpaceDetail) error { log := logger.WithType[CheckShardStore]("TickTock") if space.MasterHub == nil { log.Infof("user space %v has no master hub", space.UserSpace) return nil } agtCli, err := stgglb.HubMQPool.Acquire(space.MasterHub.HubID) if err != nil { return fmt.Errorf("new hub mq client: %w", err) } defer stgglb.HubMQPool.Release(agtCli) checkResp, err := agtCli.CheckCache(hubmq.NewCheckCache(*space), mq.RequestOption{Timeout: time.Minute}) if err != nil { return fmt.Errorf("request to check cache: %w", err) } realFileHashes := lo.SliceToMap(checkResp.FileHashes, func(hash clitypes.FileHash) (clitypes.FileHash, bool) { return hash, true }) // 在事务中执行缓存更新操作 t.db.DoTx(func(tx db.SQLContext) error { j.checkPinnedObject(t, tx, space, realFileHashes) j.checkObjectBlock(t, tx, space, realFileHashes) return nil }) return nil } // checkPinnedObject 对比PinnedObject表,若实际文件不存在,则进行删除操作 func (*CheckShardStore) checkPinnedObject(t *TickTock, tx db.SQLContext, space *clitypes.UserSpaceDetail, realFileHashes map[clitypes.FileHash]bool) { log := logger.WithType[CheckShardStore]("TickTock") objs, err := t.db.PinnedObject().GetObjectsByUserSpaceID(tx, space.UserSpace.UserSpaceID) if err != nil { log.Warnf("getting pinned objects by user space id %v: %v", space.UserSpace, err) return } var rms []clitypes.ObjectID for _, c := range objs { if realFileHashes[c.FileHash] { continue } rms = append(rms, c.ObjectID) } if len(rms) > 0 { err = t.db.PinnedObject().BatchDelete(tx, space.UserSpace.UserSpaceID, rms) if err != nil { log.Warnf("batch delete user space %v pinned objects: %v", space.UserSpace, err) } } } // checkObjectBlock 对比ObjectBlock表,若实际文件不存在,则进行删除操作 func (*CheckShardStore) checkObjectBlock(t *TickTock, tx db.SQLContext, space *clitypes.UserSpaceDetail, realFileHashes map[clitypes.FileHash]bool) { log := logger.WithType[CheckShardStore]("TickTock") blocks, err := t.db.ObjectBlock().GetByUserSpaceID(tx, space.UserSpace.UserSpaceID) if err != nil { log.Warnf("getting object blocks by user space id %v: %v", space.UserSpace, err) return } var rms []clitypes.FileHash for _, b := range blocks { if realFileHashes[b.FileHash] { continue } rms = append(rms, b.FileHash) } if len(rms) > 0 { err = t.db.ObjectBlock().BatchDeleteByFileHash(tx, space.UserSpace.UserSpaceID, rms) if err != nil { log.Warnf("batch delete user space %v object blocks: %v", space.UserSpace, err) } } }