package lockprovider import ( "fmt" "gitlink.org.cn/cloudream/common/utils/lo2" "gitlink.org.cn/cloudream/jcs-pub/client/internal/publock/types" ) const ( UserSpaceLockPathPrefix = "UserSpace" UserSpaceStorageIDPathIndex = 1 UserSpaceBuzyLock = "Buzy" UserSpaceGCLock = "GC" ) type UserSpaceLock struct { stgLocks map[string]*UserSpaceStorageLock dummyLock *UserSpaceStorageLock } func NewUserSpaceLock() *UserSpaceLock { return &UserSpaceLock{ stgLocks: make(map[string]*UserSpaceStorageLock), dummyLock: NewUserSpaceStorageLock(), } } // CanLock 判断这个锁能否锁定成功 func (l *UserSpaceLock) CanLock(lock types.Lock) error { nodeLock, ok := l.stgLocks[lock.Path[UserSpaceStorageIDPathIndex]] if !ok { // 不能直接返回nil,因为如果锁数据的格式不对,也不能获取锁。 // 这里使用一个空Provider来进行检查。 return l.dummyLock.CanLock(lock) } return nodeLock.CanLock(lock) } // 锁定。在内部可以不用判断能否加锁,外部需要保证调用此函数前调用了CanLock进行检查 func (l *UserSpaceLock) Lock(reqID types.RequestID, lock types.Lock) error { stgID := lock.Path[UserSpaceStorageIDPathIndex] nodeLock, ok := l.stgLocks[stgID] if !ok { nodeLock = NewUserSpaceStorageLock() l.stgLocks[stgID] = nodeLock } return nodeLock.Lock(reqID, lock) } // 解锁 func (l *UserSpaceLock) Unlock(reqID types.RequestID, lock types.Lock) error { stgID := lock.Path[UserSpaceStorageIDPathIndex] nodeLock, ok := l.stgLocks[stgID] if !ok { return nil } return nodeLock.Unlock(reqID, lock) } // Clear 清除内部所有状态 func (l *UserSpaceLock) Clear() { l.stgLocks = make(map[string]*UserSpaceStorageLock) } type UserSpaceStorageLock struct { buzyReqIDs []types.RequestID gcReqIDs []types.RequestID lockCompatibilityTable *LockCompatibilityTable } func NewUserSpaceStorageLock() *UserSpaceStorageLock { compTable := &LockCompatibilityTable{} sdLock := UserSpaceStorageLock{ lockCompatibilityTable: compTable, } compTable. Column(UserSpaceBuzyLock, func() bool { return len(sdLock.buzyReqIDs) > 0 }). Column(UserSpaceGCLock, func() bool { return len(sdLock.gcReqIDs) > 0 }) comp := LockCompatible() uncp := LockUncompatible() compTable.MustRow(comp, uncp) compTable.MustRow(uncp, comp) return &sdLock } // CanLock 判断这个锁能否锁定成功 func (l *UserSpaceStorageLock) CanLock(lock types.Lock) error { return l.lockCompatibilityTable.Test(lock) } // 锁定 func (l *UserSpaceStorageLock) Lock(reqID types.RequestID, lock types.Lock) error { switch lock.Name { case UserSpaceBuzyLock: l.buzyReqIDs = append(l.buzyReqIDs, reqID) case UserSpaceGCLock: l.gcReqIDs = append(l.gcReqIDs, reqID) default: return fmt.Errorf("unknow lock name: %s", lock.Name) } return nil } // 解锁 func (l *UserSpaceStorageLock) Unlock(reqID types.RequestID, lock types.Lock) error { switch lock.Name { case UserSpaceBuzyLock: l.buzyReqIDs = lo2.Remove(l.buzyReqIDs, reqID) case UserSpaceGCLock: l.gcReqIDs = lo2.Remove(l.gcReqIDs, reqID) default: return fmt.Errorf("unknow lock name: %s", lock.Name) } return nil }