|
|
|
@@ -0,0 +1,182 @@ |
|
|
|
package lockprovider |
|
|
|
|
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
|
|
|
|
"github.com/samber/lo" |
|
|
|
"gitlink.org.cn/cloudream/common/pkg/distlock" |
|
|
|
mylo "gitlink.org.cn/cloudream/common/utils/lo" |
|
|
|
) |
|
|
|
|
|
|
|
const ( |
|
|
|
METADATA_SET_READ_LOCK = "SetRead" |
|
|
|
METADATA_SET_WRITE_LOCK = "SetWrite" |
|
|
|
METADATA_SET_CREATE_LOCK = "SetCreate" |
|
|
|
|
|
|
|
METADATA_ELEMENT_READ_LOCK = "ElementRead" |
|
|
|
METADATA_ELEMENT_WRITE_LOCK = "ElementWrite" |
|
|
|
METADATA_ELEMENT_CREATE_LOCK = "ElementCreate" |
|
|
|
) |
|
|
|
|
|
|
|
type metadataElementLock struct { |
|
|
|
target StringLockTarget |
|
|
|
requestIDs []string |
|
|
|
} |
|
|
|
|
|
|
|
type MetadataLock struct { |
|
|
|
setReadReqIDs []string |
|
|
|
setWriteReqIDs []string |
|
|
|
setCreateReqIDs []string |
|
|
|
|
|
|
|
elementReadLocks []*metadataElementLock |
|
|
|
elementWriteLocks []*metadataElementLock |
|
|
|
elementCreateLocks []*metadataElementLock |
|
|
|
|
|
|
|
lockCompatibilityTable LockCompatibilityTable |
|
|
|
} |
|
|
|
|
|
|
|
func NewMetadataLock() *MetadataLock { |
|
|
|
|
|
|
|
metadataLock := MetadataLock{ |
|
|
|
lockCompatibilityTable: LockCompatibilityTable{}, |
|
|
|
} |
|
|
|
|
|
|
|
compTable := &metadataLock.lockCompatibilityTable |
|
|
|
|
|
|
|
compTable. |
|
|
|
Column(METADATA_SET_READ_LOCK, func() bool { return len(metadataLock.setReadReqIDs) > 0 }). |
|
|
|
Column(METADATA_SET_WRITE_LOCK, func() bool { return len(metadataLock.setWriteReqIDs) > 0 }). |
|
|
|
Column(METADATA_SET_CREATE_LOCK, func() bool { return len(metadataLock.setCreateReqIDs) > 0 }). |
|
|
|
Column(METADATA_ELEMENT_READ_LOCK, func() bool { return len(metadataLock.elementReadLocks) > 0 }). |
|
|
|
Column(METADATA_ELEMENT_WRITE_LOCK, func() bool { return len(metadataLock.elementWriteLocks) > 0 }). |
|
|
|
Column(METADATA_ELEMENT_CREATE_LOCK, func() bool { return len(metadataLock.elementCreateLocks) > 0 }) |
|
|
|
|
|
|
|
comp := LockCompatible() |
|
|
|
uncp := LockUncompatible() |
|
|
|
trgt := LockSpecial(func(lock distlock.Lock, testLockName string) bool { |
|
|
|
strTar := lock.Target.(StringLockTarget) |
|
|
|
if testLockName == METADATA_ELEMENT_READ_LOCK { |
|
|
|
// 如果没有任何锁的锁对象与当前的锁对象冲突,那么这个锁可以加 |
|
|
|
return lo.NoneBy(metadataLock.elementReadLocks, func(other *metadataElementLock) bool { return strTar.IsConflict(&other.target) }) |
|
|
|
} |
|
|
|
|
|
|
|
if testLockName == METADATA_ELEMENT_WRITE_LOCK { |
|
|
|
return lo.NoneBy(metadataLock.elementWriteLocks, func(other *metadataElementLock) bool { return strTar.IsConflict(&other.target) }) |
|
|
|
} |
|
|
|
|
|
|
|
return lo.NoneBy(metadataLock.elementCreateLocks, func(other *metadataElementLock) bool { return strTar.IsConflict(&other.target) }) |
|
|
|
}) |
|
|
|
|
|
|
|
compTable.MustRow(comp, trgt, comp, comp, uncp, comp) |
|
|
|
compTable.MustRow(trgt, trgt, comp, uncp, uncp, comp) |
|
|
|
compTable.MustRow(comp, comp, trgt, uncp, uncp, uncp) |
|
|
|
compTable.MustRow(comp, uncp, uncp, comp, uncp, uncp) |
|
|
|
compTable.MustRow(uncp, uncp, uncp, uncp, uncp, uncp) |
|
|
|
compTable.MustRow(comp, comp, uncp, uncp, uncp, uncp) |
|
|
|
|
|
|
|
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 METADATA_SET_READ_LOCK: |
|
|
|
l.setReadReqIDs = append(l.setReadReqIDs, reqID) |
|
|
|
case METADATA_SET_WRITE_LOCK: |
|
|
|
l.setWriteReqIDs = append(l.setWriteReqIDs, reqID) |
|
|
|
case METADATA_SET_CREATE_LOCK: |
|
|
|
l.setCreateReqIDs = append(l.setCreateReqIDs, reqID) |
|
|
|
|
|
|
|
case METADATA_ELEMENT_READ_LOCK: |
|
|
|
l.elementReadLocks = l.addElementLock(lock, l.elementReadLocks, reqID) |
|
|
|
case METADATA_ELEMENT_WRITE_LOCK: |
|
|
|
l.elementWriteLocks = l.addElementLock(lock, l.elementWriteLocks, reqID) |
|
|
|
case METADATA_ELEMENT_CREATE_LOCK: |
|
|
|
l.elementCreateLocks = l.addElementLock(lock, l.elementCreateLocks, 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 METADATA_SET_READ_LOCK: |
|
|
|
l.setReadReqIDs = mylo.Remove(l.setReadReqIDs, reqID) |
|
|
|
case METADATA_SET_WRITE_LOCK: |
|
|
|
l.setWriteReqIDs = mylo.Remove(l.setWriteReqIDs, reqID) |
|
|
|
case METADATA_SET_CREATE_LOCK: |
|
|
|
l.setCreateReqIDs = mylo.Remove(l.setCreateReqIDs, reqID) |
|
|
|
|
|
|
|
case METADATA_ELEMENT_READ_LOCK: |
|
|
|
l.elementReadLocks = l.removeElementLock(lock, l.elementReadLocks, reqID) |
|
|
|
case METADATA_ELEMENT_WRITE_LOCK: |
|
|
|
l.elementWriteLocks = l.removeElementLock(lock, l.elementWriteLocks, reqID) |
|
|
|
case METADATA_ELEMENT_CREATE_LOCK: |
|
|
|
l.elementCreateLocks = l.removeElementLock(lock, l.elementCreateLocks, 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 = mylo.Remove(lck.requestIDs, reqID) |
|
|
|
|
|
|
|
if len(lck.requestIDs) == 0 { |
|
|
|
locks = mylo.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.setReadReqIDs = nil |
|
|
|
l.setWriteReqIDs = nil |
|
|
|
l.setCreateReqIDs = nil |
|
|
|
l.elementReadLocks = nil |
|
|
|
l.elementWriteLocks = nil |
|
|
|
l.elementCreateLocks = nil |
|
|
|
} |