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.

service.go 4.1 kB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package distlock
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "gitlink.org.cn/cloudream/common/pkgs/future"
  8. "gitlink.org.cn/cloudream/common/pkgs/trie"
  9. "gitlink.org.cn/cloudream/common/utils/lo2"
  10. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/distlock/lockprovider"
  11. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/distlock/types"
  12. )
  13. type AcquireOption struct {
  14. Timeout time.Duration
  15. }
  16. type AcquireOptionFn func(opt *AcquireOption)
  17. func WithTimeout(timeout time.Duration) AcquireOptionFn {
  18. return func(opt *AcquireOption) {
  19. opt.Timeout = timeout
  20. }
  21. }
  22. type Service struct {
  23. lock *sync.Mutex
  24. provdersTrie *trie.Trie[types.LockProvider]
  25. acquirings []*acquireInfo
  26. nextReqID int64
  27. }
  28. func NewService() *Service {
  29. svc := &Service{
  30. lock: &sync.Mutex{},
  31. provdersTrie: trie.NewTrie[types.LockProvider](),
  32. }
  33. svc.provdersTrie.Create([]any{lockprovider.ShardStoreLockPathPrefix, trie.WORD_ANY}).Value = lockprovider.NewShardStoreLock()
  34. return svc
  35. }
  36. type acquireInfo struct {
  37. Request types.LockRequest
  38. Callback *future.SetValueFuture[types.RequestID]
  39. LastErr error
  40. }
  41. func (svc *Service) Acquire(req types.LockRequest, opts ...AcquireOptionFn) (*Mutex, error) {
  42. var opt = AcquireOption{
  43. Timeout: time.Second * 10,
  44. }
  45. for _, fn := range opts {
  46. fn(&opt)
  47. }
  48. ctx := context.Background()
  49. if opt.Timeout != 0 {
  50. var cancel func()
  51. ctx, cancel = context.WithTimeout(ctx, opt.Timeout)
  52. defer cancel()
  53. }
  54. // 就地检测锁是否可用
  55. svc.lock.Lock()
  56. defer svc.lock.Unlock()
  57. reqID, err := svc.tryAcquireOne(req)
  58. if err != nil {
  59. return nil, err
  60. }
  61. if reqID != "" {
  62. return &Mutex{
  63. svc: svc,
  64. lockReq: req,
  65. lockReqID: reqID,
  66. }, nil
  67. }
  68. // 就地检测失败,那么就需要异步等待锁可用
  69. info := &acquireInfo{
  70. Request: req,
  71. Callback: future.NewSetValue[types.RequestID](),
  72. }
  73. svc.acquirings = append(svc.acquirings, info)
  74. // 等待的时候不加锁
  75. svc.lock.Unlock()
  76. reqID, err = info.Callback.Wait(ctx)
  77. svc.lock.Lock()
  78. if err == nil {
  79. return &Mutex{
  80. svc: svc,
  81. lockReq: req,
  82. lockReqID: reqID,
  83. }, nil
  84. }
  85. if err != future.ErrCanceled {
  86. lo2.Remove(svc.acquirings, info)
  87. return nil, err
  88. }
  89. // 如果第一次等待是超时错误,那么在锁里再尝试获取一次结果
  90. reqID, err = info.Callback.TryGetValue()
  91. if err == nil {
  92. return &Mutex{
  93. svc: svc,
  94. lockReq: req,
  95. lockReqID: reqID,
  96. }, nil
  97. }
  98. lo2.Remove(svc.acquirings, info)
  99. return nil, err
  100. }
  101. func (s *Service) BeginReentrant() *Reentrant {
  102. return &Reentrant{
  103. svc: s,
  104. }
  105. }
  106. func (s *Service) release(reqID types.RequestID, req types.LockRequest) {
  107. s.lock.Lock()
  108. defer s.lock.Unlock()
  109. s.releaseRequest(reqID, req)
  110. s.tryAcquirings()
  111. }
  112. func (a *Service) tryAcquirings() {
  113. for i := 0; i < len(a.acquirings); i++ {
  114. req := a.acquirings[i]
  115. reqID, err := a.tryAcquireOne(req.Request)
  116. if err != nil {
  117. req.LastErr = err
  118. continue
  119. }
  120. req.Callback.SetValue(reqID)
  121. a.acquirings[i] = nil
  122. }
  123. a.acquirings = lo2.RemoveAllDefault(a.acquirings)
  124. }
  125. func (s *Service) tryAcquireOne(req types.LockRequest) (types.RequestID, error) {
  126. err := s.testOneRequest(req)
  127. if err != nil {
  128. return "", err
  129. }
  130. reqID := types.RequestID(fmt.Sprintf("%d", s.nextReqID))
  131. s.nextReqID++
  132. s.applyRequest(reqID, req)
  133. return reqID, nil
  134. }
  135. func (s *Service) testOneRequest(req types.LockRequest) error {
  136. for _, lock := range req.Locks {
  137. n, ok := s.provdersTrie.WalkEnd(lock.Path)
  138. if !ok || n.Value == nil {
  139. return fmt.Errorf("lock provider not found for path %v", lock.Path)
  140. }
  141. err := n.Value.CanLock(lock)
  142. if err != nil {
  143. return err
  144. }
  145. }
  146. return nil
  147. }
  148. func (s *Service) applyRequest(reqID types.RequestID, req types.LockRequest) {
  149. for _, lock := range req.Locks {
  150. p, _ := s.provdersTrie.WalkEnd(lock.Path)
  151. p.Value.Lock(reqID, lock)
  152. }
  153. }
  154. func (s *Service) releaseRequest(reqID types.RequestID, req types.LockRequest) {
  155. for _, lock := range req.Locks {
  156. p, _ := s.provdersTrie.WalkEnd(lock.Path)
  157. p.Value.Unlock(reqID, lock)
  158. }
  159. }

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