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.

104 lines
2.8 KiB

5 years ago
  1. package shell
  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. AdminLockName = "admin"
  15. )
  16. type ExclusiveLocker struct {
  17. masterClient *wdclient.MasterClient
  18. token int64
  19. lockTsNs int64
  20. isLocking bool
  21. }
  22. func NewExclusiveLocker(masterClient *wdclient.MasterClient) *ExclusiveLocker {
  23. return &ExclusiveLocker{
  24. masterClient: masterClient,
  25. }
  26. }
  27. func (l *ExclusiveLocker) GetToken() (token int64, lockTsNs int64) {
  28. for time.Unix(0, atomic.LoadInt64(&l.lockTsNs)).Add(SafeRenewInteval).Before(time.Now()) {
  29. // wait until now is within the safe lock period, no immediate renewal to change the token
  30. time.Sleep(100 * time.Millisecond)
  31. }
  32. return atomic.LoadInt64(&l.token), atomic.LoadInt64(&l.lockTsNs)
  33. }
  34. func (l *ExclusiveLocker) RequestLock() {
  35. // retry to get the lease
  36. for {
  37. if err := l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  38. resp, err := client.LeaseAdminToken(context.Background(), &master_pb.LeaseAdminTokenRequest{
  39. PreviousToken: atomic.LoadInt64(&l.token),
  40. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  41. LockName: AdminLockName,
  42. })
  43. if err == nil {
  44. atomic.StoreInt64(&l.token, resp.Token)
  45. atomic.StoreInt64(&l.lockTsNs, resp.LockTsNs)
  46. }
  47. return err
  48. }); err != nil {
  49. // println("leasing problem", err.Error())
  50. time.Sleep(InitLockInteval)
  51. } else {
  52. break
  53. }
  54. }
  55. l.isLocking = true
  56. // start a goroutine to renew the lease
  57. go func() {
  58. for l.isLocking {
  59. if err := l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  60. resp, err := client.LeaseAdminToken(context.Background(), &master_pb.LeaseAdminTokenRequest{
  61. PreviousToken: atomic.LoadInt64(&l.token),
  62. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  63. LockName: AdminLockName,
  64. })
  65. if err == nil {
  66. atomic.StoreInt64(&l.token, resp.Token)
  67. atomic.StoreInt64(&l.lockTsNs, resp.LockTsNs)
  68. // println("ts", l.lockTsNs, "token", l.token)
  69. }
  70. return err
  71. }); err != nil {
  72. glog.Errorf("failed to renew lock: %v", err)
  73. return
  74. } else {
  75. time.Sleep(RenewInteval)
  76. }
  77. }
  78. }()
  79. }
  80. func (l *ExclusiveLocker) ReleaseLock() {
  81. l.isLocking = false
  82. l.masterClient.WithClient(func(client master_pb.SeaweedClient) error {
  83. client.ReleaseAdminToken(context.Background(), &master_pb.ReleaseAdminTokenRequest{
  84. PreviousToken: atomic.LoadInt64(&l.token),
  85. PreviousLockTime: atomic.LoadInt64(&l.lockTsNs),
  86. LockName: AdminLockName,
  87. })
  88. return nil
  89. })
  90. atomic.StoreInt64(&l.token, 0)
  91. atomic.StoreInt64(&l.lockTsNs, 0)
  92. }