JCS-pub/common/pkgs/distlock/lockprovider/lock_compatibility_table.go

124 lines
3.0 KiB
Go

package lockprovider
import (
"fmt"
"github.com/samber/lo"
"gitlink.org.cn/cloudream/jcs-pub/common/pkgs/distlock/types"
)
const (
LOCK_COMPATIBILITY_COMPATIBLE LockCompatibilityType = "Compatible"
LOCK_COMPATIBILITY_UNCOMPATIBLE LockCompatibilityType = "Uncompatible"
LOCK_COMPATIBILITY_SPECIAL LockCompatibilityType = "Special"
)
type HasSuchLockFn = func() bool
// LockCompatibilitySpecialFn 判断锁与指定的锁名是否兼容
type LockCompatibilitySpecialFn func(lock types.Lock, testLockName string) bool
type LockCompatibilityType string
type LockCompatibility struct {
Type LockCompatibilityType
SpecialFn LockCompatibilitySpecialFn
}
func LockCompatible() LockCompatibility {
return LockCompatibility{
Type: LOCK_COMPATIBILITY_COMPATIBLE,
}
}
func LockUncompatible() LockCompatibility {
return LockCompatibility{
Type: LOCK_COMPATIBILITY_UNCOMPATIBLE,
}
}
func LockSpecial(specialFn LockCompatibilitySpecialFn) LockCompatibility {
return LockCompatibility{
Type: LOCK_COMPATIBILITY_SPECIAL,
SpecialFn: specialFn,
}
}
type LockCompatibilityTableRow struct {
LockName string
HasSuchLockFn HasSuchLockFn
Compatibilities []LockCompatibility
}
type LockCompatibilityTable struct {
rows []LockCompatibilityTableRow
rowIndex int
}
func (t *LockCompatibilityTable) Column(lockName string, hasSuchLock HasSuchLockFn) *LockCompatibilityTable {
t.rows = append(t.rows, LockCompatibilityTableRow{
LockName: lockName,
HasSuchLockFn: hasSuchLock,
})
return t
}
func (t *LockCompatibilityTable) MustRow(comps ...LockCompatibility) {
err := t.Row(comps...)
if err != nil {
panic(fmt.Sprintf("build lock compatibility table failed, err: %s", err.Error()))
}
}
func (t *LockCompatibilityTable) Row(comps ...LockCompatibility) error {
if t.rowIndex >= len(t.rows) {
return fmt.Errorf("there should be no more rows in the table")
}
if len(comps) < len(t.rows) {
return fmt.Errorf("the columns should equals the rows")
}
t.rows[t.rowIndex].Compatibilities = comps
for i := 0; i < t.rowIndex-1; i++ {
chkRowCeil := t.rows[t.rowIndex].Compatibilities[i]
chkColCeil := t.rows[i].Compatibilities[t.rowIndex]
if chkRowCeil.Type != chkColCeil.Type {
return fmt.Errorf("value at %d, %d is not equals to at %d, %d", t.rowIndex, i, i, t.rowIndex)
}
}
t.rowIndex++
return nil
}
func (t *LockCompatibilityTable) Test(lock types.Lock) error {
row, ok := lo.Find(t.rows, func(row LockCompatibilityTableRow) bool { return lock.Name == row.LockName })
if !ok {
return fmt.Errorf("unknow lock name %s", lock.Name)
}
for i, c := range row.Compatibilities {
if c.Type == LOCK_COMPATIBILITY_COMPATIBLE {
continue
}
if c.Type == LOCK_COMPATIBILITY_UNCOMPATIBLE {
if t.rows[i].HasSuchLockFn() {
return types.NewLockTargetBusyError(t.rows[i].LockName)
}
}
if c.Type == LOCK_COMPATIBILITY_SPECIAL {
if !c.SpecialFn(lock, t.rows[i].LockName) {
return types.NewLockTargetBusyError(t.rows[i].LockName)
}
}
}
return nil
}