You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.2 KiB

5 years ago
3 years ago
3 years ago
3 years ago
3 years ago
5 years ago
5 years ago
5 years ago
3 years ago
3 years ago
5 years ago
3 years ago
  1. package exclusive_locks
  2. import (
  3. "context"
  4. "sync/atomic"
  5. "time"
  6. "github.com/chrislusf/seaweedfs/weed/glog"
  7. "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
  8. "github.com/chrislusf/seaweedfs/weed/wdclient"
  9. )
  10. const (
  11. RenewInteval = 4 * time.Second
  12. SafeRenewInteval = 3 * time.Second
  13. InitLockInteval = 1 * time.Second
  14. )
  15. type ExclusiveLocker struct {
  16. token int64
  17. lockTsNs int64
  18. isLocking bool
  19. masterClient *wdclient.MasterClient
  20. lockName string
  21. }
  22. func NewExclusiveLocker(masterClient *wdclient.MasterClient, lockName string) *ExclusiveLocker {
  23. return &ExclusiveLocker{
  24. masterClient: masterClient,
  25. lockName: lockName,
  26. }
  27. }
  28. func (l *ExclusiveLocker) IsLocking() bool {
  29. return l.isLocking
  30. }
  31. func (l *ExclusiveLocker) GetToken() (token int64, lockTsNs int64) {
  32. for time.Unix(0, atomic.LoadInt64(&l.lockTsNs)).Add(SafeRenewInteval).Before(time.Now()) {
  33. // wait until now is within the safe lock period, no immediate renewal to change the token
  34. time.Sleep(100 * time.Millisecond)
  35. }
  36. return atomic.LoadInt64(&l.token), atomic.LoadInt64(&l.lockTsNs)
  37. }
  38. func (l *ExclusiveLocker) RequestLock(clientName string) {
  39. if l.isLocking {
  40. return
  41. }
  42. ctx, cancel := context.WithCancel(context.Background())
  43. defer cancel()
  44. // retry to get the lease
  45. for {
  46. if err := l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  47. resp, err := client.LeaseAdminToken(ctx, &master_pb.LeaseAdminTokenRequest{
  48. PreviousToken: atomic.LoadInt64(&l.token),
  49. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  50. LockName: l.lockName,
  51. ClientName: clientName,
  52. })
  53. if err == nil {
  54. atomic.StoreInt64(&l.token, resp.Token)
  55. atomic.StoreInt64(&l.lockTsNs, resp.LockTsNs)
  56. }
  57. return err
  58. }); err != nil {
  59. println("lock:", err.Error())
  60. time.Sleep(InitLockInteval)
  61. } else {
  62. break
  63. }
  64. }
  65. l.isLocking = true
  66. // start a goroutine to renew the lease
  67. go func() {
  68. ctx2, cancel2 := context.WithCancel(context.Background())
  69. defer cancel2()
  70. for l.isLocking {
  71. if err := l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  72. resp, err := client.LeaseAdminToken(ctx2, &master_pb.LeaseAdminTokenRequest{
  73. PreviousToken: atomic.LoadInt64(&l.token),
  74. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  75. LockName: l.lockName,
  76. ClientName: clientName,
  77. })
  78. if err == nil {
  79. atomic.StoreInt64(&l.token, resp.Token)
  80. atomic.StoreInt64(&l.lockTsNs, resp.LockTsNs)
  81. // println("ts", l.lockTsNs, "token", l.token)
  82. }
  83. return err
  84. }); err != nil {
  85. glog.Errorf("failed to renew lock: %v", err)
  86. return
  87. } else {
  88. time.Sleep(RenewInteval)
  89. }
  90. }
  91. }()
  92. }
  93. func (l *ExclusiveLocker) ReleaseLock() {
  94. l.isLocking = false
  95. ctx, cancel := context.WithCancel(context.Background())
  96. defer cancel()
  97. l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  98. client.ReleaseAdminToken(ctx, &master_pb.ReleaseAdminTokenRequest{
  99. PreviousToken: atomic.LoadInt64(&l.token),
  100. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  101. LockName: l.lockName,
  102. })
  103. return nil
  104. })
  105. atomic.StoreInt64(&l.token, 0)
  106. atomic.StoreInt64(&l.lockTsNs, 0)
  107. }