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.

release_actor.go 3.3 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package internal
  2. import (
  3. "context"
  4. "fmt"
  5. "math/rand"
  6. "strconv"
  7. "sync"
  8. "time"
  9. "gitlink.org.cn/cloudream/common/pkgs/distlock"
  10. "gitlink.org.cn/cloudream/common/pkgs/logger"
  11. clientv3 "go.etcd.io/etcd/client/v3"
  12. "go.etcd.io/etcd/client/v3/clientv3util"
  13. )
  14. const (
  15. DefaultMaxReleaseingDelayMs = 4000
  16. BaseReleaseingDelayMs = 1000
  17. )
  18. type ReleaseActor struct {
  19. cfg *distlock.Config
  20. etcdCli *clientv3.Client
  21. releasingLockRequestIDs map[string]bool
  22. timer *time.Timer
  23. timerSetuped bool
  24. lock sync.Mutex
  25. }
  26. func NewReleaseActor(cfg *distlock.Config, etcdCli *clientv3.Client) *ReleaseActor {
  27. return &ReleaseActor{
  28. cfg: cfg,
  29. etcdCli: etcdCli,
  30. releasingLockRequestIDs: make(map[string]bool),
  31. }
  32. }
  33. // 立刻尝试释放这些锁。一般用于在用户主动释放了一个锁之后
  34. func (a *ReleaseActor) Release(reqIDs []string) {
  35. a.lock.Lock()
  36. defer a.lock.Unlock()
  37. for _, id := range reqIDs {
  38. a.releasingLockRequestIDs[id] = true
  39. }
  40. // TODO 处理错误
  41. err := a.doReleasing()
  42. if err != nil {
  43. logger.Std.Debugf("doing releasing: %s", err.Error())
  44. }
  45. a.setupTimer()
  46. }
  47. // 延迟释放锁。一般用于清理崩溃的锁服务遗留下来的锁
  48. func (a *ReleaseActor) DelayRelease(reqIDs []string) {
  49. a.lock.Lock()
  50. defer a.lock.Unlock()
  51. for _, id := range reqIDs {
  52. a.releasingLockRequestIDs[id] = true
  53. }
  54. a.setupTimer()
  55. }
  56. func (a *ReleaseActor) doReleasing() error {
  57. ctx := context.TODO()
  58. if len(a.releasingLockRequestIDs) == 0 {
  59. return nil
  60. }
  61. // TODO 根据不同的错误设置不同的错误类型,方便上层进行后续处理
  62. unlock, err := acquireEtcdRequestDataLock(ctx, a.etcdCli, a.cfg.EtcdLockLeaseTimeSec)
  63. if err != nil {
  64. return fmt.Errorf("acquire etcd request data lock failed, err: %w", err)
  65. }
  66. defer unlock()
  67. index, err := getEtcdLockRequestIndex(ctx, a.etcdCli)
  68. if err != nil {
  69. return err
  70. }
  71. // TODO 可以考虑优化成一次性删除多个锁
  72. for id := range a.releasingLockRequestIDs {
  73. lockReqKey := makeEtcdLockRequestKey(id)
  74. txResp, err := a.etcdCli.Txn(ctx).
  75. If(clientv3util.KeyExists(lockReqKey)).
  76. Then(clientv3.OpDelete(lockReqKey), clientv3.OpPut(EtcdLockRequestIndex, strconv.FormatInt(index+1, 10))).Commit()
  77. if err != nil {
  78. return fmt.Errorf("updating lock request data: %w", err)
  79. }
  80. // 只有确实删除了锁数据,才更新index
  81. if txResp.Succeeded {
  82. index++
  83. }
  84. delete(a.releasingLockRequestIDs, id)
  85. }
  86. return nil
  87. }
  88. func (a *ReleaseActor) setupTimer() {
  89. if len(a.releasingLockRequestIDs) == 0 {
  90. return
  91. }
  92. if a.timerSetuped {
  93. return
  94. }
  95. a.timerSetuped = true
  96. delay := int64(0)
  97. if a.cfg.RandomReleasingDelayMs == 0 {
  98. delay = rand.Int63n(DefaultMaxReleaseingDelayMs)
  99. } else {
  100. delay = rand.Int63n(a.cfg.RandomReleasingDelayMs)
  101. }
  102. if a.timer == nil {
  103. a.timer = time.NewTimer(time.Duration(delay+BaseReleaseingDelayMs) * time.Millisecond)
  104. } else {
  105. a.timer.Reset(time.Duration(delay+BaseReleaseingDelayMs) * time.Millisecond)
  106. }
  107. go func() {
  108. <-a.timer.C
  109. a.timerSetuped = false
  110. // TODO 处理错误
  111. err := a.doReleasing()
  112. if err != nil {
  113. logger.Std.Debugf("doing releasing: %s", err.Error())
  114. }
  115. a.setupTimer()
  116. }()
  117. }