|
- package lockprovider
-
- import (
- "fmt"
-
- "github.com/samber/lo"
- "gitlink.org.cn/cloudream/common/pkgs/distlock"
- "gitlink.org.cn/cloudream/common/utils/lo2"
- )
-
- const (
- MetadataLockPathPrefix = "Metadata"
- MetadataCreateLock = "Create"
- )
-
- type metadataElementLock struct {
- target StringLockTarget
- requestIDs []string
- }
-
- type MetadataLock struct {
- createReqIDs []*metadataElementLock
-
- lockCompatibilityTable LockCompatibilityTable
- }
-
- func NewMetadataLock() *MetadataLock {
-
- metadataLock := MetadataLock{
- lockCompatibilityTable: LockCompatibilityTable{},
- }
-
- compTable := &metadataLock.lockCompatibilityTable
-
- compTable.
- Column(MetadataCreateLock, func() bool { return len(metadataLock.createReqIDs) > 0 })
- trgt := LockSpecial(func(lock distlock.Lock, testLockName string) bool {
- strTar := lock.Target.(StringLockTarget)
- return lo.NoneBy(metadataLock.createReqIDs, func(other *metadataElementLock) bool { return strTar.IsConflict(&other.target) })
- })
-
- compTable.MustRow(trgt)
-
- return &metadataLock
- }
-
- // CanLock 判断这个锁能否锁定成功
- func (l *MetadataLock) CanLock(lock distlock.Lock) error {
- return l.lockCompatibilityTable.Test(lock)
- }
-
- // 锁定
- func (l *MetadataLock) Lock(reqID string, lock distlock.Lock) error {
- switch lock.Name {
- case MetadataCreateLock:
- l.createReqIDs = l.addElementLock(lock, l.createReqIDs, reqID)
-
- default:
- return fmt.Errorf("unknow lock name: %s", lock.Name)
- }
-
- return nil
- }
-
- func (l *MetadataLock) addElementLock(lock distlock.Lock, locks []*metadataElementLock, reqID string) []*metadataElementLock {
- strTarget := lock.Target.(StringLockTarget)
- lck, ok := lo.Find(locks, func(l *metadataElementLock) bool { return strTarget.IsConflict(&l.target) })
- if !ok {
- lck = &metadataElementLock{
- target: strTarget,
- }
- locks = append(locks, lck)
- }
-
- lck.requestIDs = append(lck.requestIDs, reqID)
- return locks
- }
-
- // 解锁
- func (l *MetadataLock) Unlock(reqID string, lock distlock.Lock) error {
- switch lock.Name {
- case MetadataCreateLock:
- l.createReqIDs = l.removeElementLock(lock, l.createReqIDs, reqID)
-
- default:
- return fmt.Errorf("unknow lock name: %s", lock.Name)
- }
-
- return nil
- }
-
- func (l *MetadataLock) removeElementLock(lock distlock.Lock, locks []*metadataElementLock, reqID string) []*metadataElementLock {
- strTarget := lock.Target.(StringLockTarget)
- lck, index, ok := lo.FindIndexOf(locks, func(l *metadataElementLock) bool { return strTarget.IsConflict(&l.target) })
- if !ok {
- return locks
- }
-
- lck.requestIDs = lo2.Remove(lck.requestIDs, reqID)
-
- if len(lck.requestIDs) == 0 {
- locks = lo2.RemoveAt(locks, index)
- }
-
- return locks
- }
-
- // GetTargetString 将锁对象序列化为字符串,方便存储到ETCD
- func (l *MetadataLock) GetTargetString(target any) (string, error) {
- tar := target.(StringLockTarget)
- return StringLockTargetToString(&tar)
- }
-
- // ParseTargetString 解析字符串格式的锁对象数据
- func (l *MetadataLock) ParseTargetString(targetStr string) (any, error) {
- return StringLockTargetFromString(targetStr)
- }
-
- // Clear 清除内部所有状态
- func (l *MetadataLock) Clear() {
- l.createReqIDs = nil
- }
|