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.1 kB

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

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