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.4 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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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/logger"
  9. "gitlink.org.cn/cloudream/jcs-pub/client/internal/publock/types"
  10. clirpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/client"
  11. )
  12. type AcquireOption struct {
  13. Timeout time.Duration
  14. Reason string
  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. func WithReason(reason string) AcquireOptionFn {
  23. return func(opt *AcquireOption) {
  24. opt.Reason = reason
  25. }
  26. }
  27. type PubLock struct {
  28. core *Core
  29. cliCli *clirpc.Client
  30. pubChan clirpc.PubLockMessageChan
  31. lock sync.Mutex
  32. acquirings map[string]*acquireInfo
  33. releasing map[string]*releaseInfo
  34. nextCtxID int64
  35. }
  36. func NewMaster() *PubLock {
  37. core := NewCore()
  38. return &PubLock{
  39. core: core,
  40. }
  41. }
  42. func NewSlave(cli *clirpc.Client) *PubLock {
  43. return &PubLock{
  44. cliCli: cli,
  45. acquirings: make(map[string]*acquireInfo),
  46. releasing: make(map[string]*releaseInfo),
  47. }
  48. }
  49. func (s *PubLock) BeginReentrant() *Reentrant {
  50. r := &Reentrant{
  51. p: s,
  52. }
  53. r.T = r
  54. return r
  55. }
  56. func (p *PubLock) BeginMutex() *MutexBuilder {
  57. m := &MutexBuilder{
  58. pub: p,
  59. }
  60. m.T = m
  61. return m
  62. }
  63. func (p *PubLock) Start() {
  64. if p.core != nil {
  65. p.core.Start()
  66. return
  67. }
  68. }
  69. func (p *PubLock) Stop() {
  70. p.lock.Lock()
  71. defer p.lock.Unlock()
  72. if p.core != nil {
  73. p.core.Stop()
  74. return
  75. }
  76. if p.pubChan != nil {
  77. p.pubChan.Close()
  78. p.pubChan = nil
  79. }
  80. p.cliCli.Release()
  81. p.cliCli = nil
  82. }
  83. func (p *PubLock) acquire(req types.LockRequest, opts ...AcquireOptionFn) (LockedRequest, error) {
  84. p.lock.Lock()
  85. if p.core != nil {
  86. p.lock.Unlock()
  87. return p.core.Acquire(req, opts...)
  88. }
  89. if p.pubChan == nil {
  90. p.pubChan = p.cliCli.PubLockChannel(context.Background())
  91. go p.receivingChan()
  92. }
  93. acqID := fmt.Sprintf("%v", p.nextCtxID)
  94. p.nextCtxID++
  95. cerr := p.pubChan.Send(&types.AcquireMsg{ContextID: acqID, Request: req})
  96. if cerr != nil {
  97. p.lock.Unlock()
  98. return LockedRequest{}, cerr.ToError()
  99. }
  100. callback := future.NewSetValue[types.RequestID]()
  101. info := &acquireInfo{
  102. Request: req,
  103. Callback: callback,
  104. }
  105. p.acquirings[acqID] = info
  106. p.lock.Unlock()
  107. reqID, err := callback.Wait(context.Background())
  108. if err != nil {
  109. return LockedRequest{}, err
  110. }
  111. return LockedRequest{
  112. Req: req,
  113. ReqID: reqID,
  114. }, nil
  115. }
  116. func (p *PubLock) release(reqID types.RequestID) {
  117. log := logger.WithField("Mod", "PubLock")
  118. p.lock.Lock()
  119. if p.core != nil {
  120. p.lock.Unlock()
  121. p.core.release(reqID)
  122. return
  123. }
  124. if p.pubChan == nil {
  125. p.pubChan = p.cliCli.PubLockChannel(context.Background())
  126. go p.receivingChan()
  127. }
  128. relID := fmt.Sprintf("%v", p.nextCtxID)
  129. p.nextCtxID++
  130. cerr := p.pubChan.Send(&types.ReleaseMsg{ContextID: relID, RequestID: reqID})
  131. if cerr != nil {
  132. p.lock.Unlock()
  133. log.Warnf("unlock %v: %v", reqID, cerr.ToError())
  134. return
  135. }
  136. callback := future.NewSetVoid()
  137. info := &releaseInfo{
  138. RequestID: reqID,
  139. Callback: callback,
  140. }
  141. p.releasing[relID] = info
  142. p.lock.Unlock()
  143. err := callback.Wait(context.Background())
  144. if err != nil {
  145. log.Warnf("unlock %v: %v", reqID, err)
  146. return
  147. }
  148. log.Tracef("unlock %v", reqID)
  149. }
  150. func (p *PubLock) receivingChan() {
  151. log := logger.WithField("Mod", "PubLock")
  152. for {
  153. msg, cerr := p.pubChan.Receive()
  154. if cerr != nil {
  155. p.lock.Lock()
  156. for _, info := range p.acquirings {
  157. info.Callback.SetError(cerr.ToError())
  158. }
  159. p.acquirings = make(map[string]*acquireInfo)
  160. for _, info := range p.releasing {
  161. info.Callback.SetError(cerr.ToError())
  162. }
  163. p.releasing = make(map[string]*releaseInfo)
  164. p.lock.Unlock()
  165. log.Warnf("receive channel error: %v", cerr.ToError())
  166. return
  167. }
  168. p.lock.Lock()
  169. switch msg := msg.(type) {
  170. case *types.AcquireResultMsg:
  171. info, ok := p.acquirings[msg.ContextID]
  172. if !ok {
  173. continue
  174. }
  175. if msg.Success {
  176. info.Callback.SetValue(msg.RequestID)
  177. } else {
  178. info.Callback.SetError(fmt.Errorf(msg.Reason))
  179. }
  180. delete(p.acquirings, msg.ContextID)
  181. case *types.ReleaseResultMsg:
  182. info, ok := p.releasing[msg.ContextID]
  183. if !ok {
  184. continue
  185. }
  186. info.Callback.SetVoid()
  187. delete(p.releasing, msg.ContextID)
  188. }
  189. p.lock.Unlock()
  190. }
  191. }
  192. type releaseInfo struct {
  193. RequestID types.RequestID
  194. Callback *future.SetVoidFuture
  195. }

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