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.

core.go 4.2 kB

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

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