You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

metadata_lock.go 3.1 kB

2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package lockprovider
  2. import (
  3. "fmt"
  4. "github.com/samber/lo"
  5. "gitlink.org.cn/cloudream/common/pkgs/distlock"
  6. "gitlink.org.cn/cloudream/common/utils/lo2"
  7. )
  8. const (
  9. MetadataLockPathPrefix = "Metadata"
  10. MetadataCreateLock = "Create"
  11. )
  12. type metadataElementLock struct {
  13. target StringLockTarget
  14. requestIDs []string
  15. }
  16. type MetadataLock struct {
  17. createReqIDs []*metadataElementLock
  18. lockCompatibilityTable LockCompatibilityTable
  19. }
  20. func NewMetadataLock() *MetadataLock {
  21. metadataLock := MetadataLock{
  22. lockCompatibilityTable: LockCompatibilityTable{},
  23. }
  24. compTable := &metadataLock.lockCompatibilityTable
  25. compTable.
  26. Column(MetadataCreateLock, func() bool { return len(metadataLock.createReqIDs) > 0 })
  27. trgt := LockSpecial(func(lock distlock.Lock, testLockName string) bool {
  28. strTar := lock.Target.(StringLockTarget)
  29. return lo.NoneBy(metadataLock.createReqIDs, func(other *metadataElementLock) bool { return strTar.IsConflict(&other.target) })
  30. })
  31. compTable.MustRow(trgt)
  32. return &metadataLock
  33. }
  34. // CanLock 判断这个锁能否锁定成功
  35. func (l *MetadataLock) CanLock(lock distlock.Lock) error {
  36. return l.lockCompatibilityTable.Test(lock)
  37. }
  38. // 锁定
  39. func (l *MetadataLock) Lock(reqID string, lock distlock.Lock) error {
  40. switch lock.Name {
  41. case MetadataCreateLock:
  42. l.createReqIDs = l.addElementLock(lock, l.createReqIDs, reqID)
  43. default:
  44. return fmt.Errorf("unknow lock name: %s", lock.Name)
  45. }
  46. return nil
  47. }
  48. func (l *MetadataLock) addElementLock(lock distlock.Lock, locks []*metadataElementLock, reqID string) []*metadataElementLock {
  49. strTarget := lock.Target.(StringLockTarget)
  50. lck, ok := lo.Find(locks, func(l *metadataElementLock) bool { return strTarget.IsConflict(&l.target) })
  51. if !ok {
  52. lck = &metadataElementLock{
  53. target: strTarget,
  54. }
  55. locks = append(locks, lck)
  56. }
  57. lck.requestIDs = append(lck.requestIDs, reqID)
  58. return locks
  59. }
  60. // 解锁
  61. func (l *MetadataLock) Unlock(reqID string, lock distlock.Lock) error {
  62. switch lock.Name {
  63. case MetadataCreateLock:
  64. l.createReqIDs = l.removeElementLock(lock, l.createReqIDs, reqID)
  65. default:
  66. return fmt.Errorf("unknow lock name: %s", lock.Name)
  67. }
  68. return nil
  69. }
  70. func (l *MetadataLock) removeElementLock(lock distlock.Lock, locks []*metadataElementLock, reqID string) []*metadataElementLock {
  71. strTarget := lock.Target.(StringLockTarget)
  72. lck, index, ok := lo.FindIndexOf(locks, func(l *metadataElementLock) bool { return strTarget.IsConflict(&l.target) })
  73. if !ok {
  74. return locks
  75. }
  76. lck.requestIDs = lo2.Remove(lck.requestIDs, reqID)
  77. if len(lck.requestIDs) == 0 {
  78. locks = lo2.RemoveAt(locks, index)
  79. }
  80. return locks
  81. }
  82. // GetTargetString 将锁对象序列化为字符串,方便存储到ETCD
  83. func (l *MetadataLock) GetTargetString(target any) (string, error) {
  84. tar := target.(StringLockTarget)
  85. return StringLockTargetToString(&tar)
  86. }
  87. // ParseTargetString 解析字符串格式的锁对象数据
  88. func (l *MetadataLock) ParseTargetString(targetStr string) (any, error) {
  89. return StringLockTargetFromString(targetStr)
  90. }
  91. // Clear 清除内部所有状态
  92. func (l *MetadataLock) Clear() {
  93. l.createReqIDs = nil
  94. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。