1package lock
2
3import (
4 "errors"
5 "time"
6)
7
8const (
9 // DefaultLockID is the id used to lock the database for migrations. It is a crc64 hash of the
10 // string "goose". This is used to ensure that the lock is unique to goose.
11 //
12 // crc64.Checksum([]byte("goose"), crc64.MakeTable(crc64.ECMA))
13 DefaultLockID int64 = 5887940537704921958
14)
15
16// SessionLockerOption is used to configure a SessionLocker.
17type SessionLockerOption interface {
18 apply(*sessionLockerConfig) error
19}
20
21// WithLockID sets the lock ID to use when locking the database.
22//
23// If WithLockID is not called, the DefaultLockID is used.
24func WithLockID(lockID int64) SessionLockerOption {
25 return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
26 c.lockID = lockID
27 return nil
28 })
29}
30
31// WithLockTimeout sets the max duration to wait for the lock to be acquired. The total duration
32// will be the period times the failure threshold.
33//
34// By default, the lock timeout is 300s (5min), where the lock is retried every 5 seconds (period)
35// up to 60 times (failure threshold).
36//
37// The minimum period is 1 second, and the minimum failure threshold is 1.
38func WithLockTimeout(period, failureThreshold uint64) SessionLockerOption {
39 return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
40 if period < 1 {
41 return errors.New("period must be greater than 0, minimum is 1")
42 }
43 if failureThreshold < 1 {
44 return errors.New("failure threshold must be greater than 0, minimum is 1")
45 }
46 c.lockProbe = probe{
47 intervalDuration: time.Duration(period) * time.Second,
48 failureThreshold: failureThreshold,
49 }
50 return nil
51 })
52}
53
54// WithUnlockTimeout sets the max duration to wait for the lock to be released. The total duration
55// will be the period times the failure threshold.
56//
57// By default, the lock timeout is 60s, where the lock is retried every 2 seconds (period) up to 30
58// times (failure threshold).
59//
60// The minimum period is 1 second, and the minimum failure threshold is 1.
61func WithUnlockTimeout(period, failureThreshold uint64) SessionLockerOption {
62 return sessionLockerConfigFunc(func(c *sessionLockerConfig) error {
63 if period < 1 {
64 return errors.New("period must be greater than 0, minimum is 1")
65 }
66 if failureThreshold < 1 {
67 return errors.New("failure threshold must be greater than 0, minimum is 1")
68 }
69 c.unlockProbe = probe{
70 intervalDuration: time.Duration(period) * time.Second,
71 failureThreshold: failureThreshold,
72 }
73 return nil
74 })
75}
76
77type sessionLockerConfig struct {
78 lockID int64
79 lockProbe probe
80 unlockProbe probe
81}
82
83// probe is used to configure how often and how many times to retry a lock or unlock operation. The
84// total timeout will be the period times the failure threshold.
85type probe struct {
86 // How often (in seconds) to perform the probe.
87 intervalDuration time.Duration
88 // Number of times to retry the probe.
89 failureThreshold uint64
90}
91
92var _ SessionLockerOption = (sessionLockerConfigFunc)(nil)
93
94type sessionLockerConfigFunc func(*sessionLockerConfig) error
95
96func (f sessionLockerConfigFunc) apply(cfg *sessionLockerConfig) error {
97 return f(cfg)
98}