lock.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package lock
  2. import (
  3. "fmt"
  4. "github.com/ente-io/museum/pkg/repo"
  5. "github.com/ente-io/stacktrace"
  6. log "github.com/sirupsen/logrus"
  7. )
  8. // LockController exposes functions to obtain locks before entering critical sections
  9. type LockController struct {
  10. TaskLockingRepo *repo.TaskLockRepository
  11. HostName string
  12. }
  13. // Try to obtain a lock with the given lockID.
  14. //
  15. // Return false if the lock is already taken.
  16. //
  17. // A call to this function should be matched by a call to ReleaseLock. A common
  18. // pattern is to put the ReleaseLock into a defer statement immediately
  19. // following the lock acquisition.
  20. //
  21. // However, it is also fine to omit the release. Such would be useful for cases
  22. // where we want to ensure the same job cannot run again until the expiry time
  23. // is past.
  24. func (c *LockController) TryLock(lockID string, lockUntil int64) bool {
  25. lockStatus, err := c.TaskLockingRepo.AcquireLock(lockID, lockUntil, c.HostName)
  26. if err != nil || !lockStatus {
  27. return false
  28. }
  29. return true
  30. }
  31. // ExtendLock refreshes an existing lock by updating its locked_at to now and
  32. // extending its lockUntil.
  33. //
  34. // It is only valid to call this method when holding an existing lock previously
  35. // obtained using TryLock.
  36. func (c *LockController) ExtendLock(lockID string, lockUntil int64) error {
  37. foundLock, err := c.TaskLockingRepo.ExtendLock(lockID, lockUntil, c.HostName)
  38. if err != nil {
  39. return stacktrace.Propagate(err, "Unable to extend lock %v", lockID)
  40. }
  41. if !foundLock {
  42. return fmt.Errorf("no existing lock for %v", lockID)
  43. }
  44. return nil
  45. }
  46. // Release a lock that was obtained earlier using TryLock.
  47. func (c *LockController) ReleaseLock(lockID string) {
  48. err := c.TaskLockingRepo.ReleaseLock(lockID)
  49. if err != nil {
  50. log.Errorf("Error while releasing lock %v: %s", lockID, err)
  51. }
  52. }
  53. func (c *LockController) ReleaseHostLock() {
  54. count, err := c.TaskLockingRepo.ReleaseLocksBy(c.HostName)
  55. if err != nil {
  56. log.Errorf("Error while releasing host lock: %s", err)
  57. }
  58. log.Infof("Released %d locks held by %s", *count, c.HostName)
  59. }