forked from tcolgate/godinstall
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgovernor.go
79 lines (68 loc) · 1.54 KB
/
governor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package main
import (
"errors"
"sync"
)
type req struct{}
// Governor is used for rate liiting requests, and for locking
// the repository from new requests when an regeneration is
// occuring
type Governor struct {
Max int // Maximum number of concurrent requests
reqs chan req // Channel for tracking in-flight requests
rwLock sync.RWMutex // A RW mutex for locking out reads during an update
}
// NewGovernor creates a governor that will limit users to max current
// readers at any one time
func NewGovernor(max int) *Governor {
var g Governor
g.Max = max
if g.Max != 0 {
g.reqs = make(chan req, g.Max)
for i := 0; i < g.Max; i++ {
g.reqs <- req{}
}
}
return &g
}
// ReadLock takes a read lock on this governor
func (g *Governor) ReadLock() {
// debug.PrintStack()
if g.Max != 0 {
_ = <-g.reqs
}
g.rwLock.RLock()
}
// ReadUnLock releases a read lock
func (g *Governor) ReadUnLock() {
// debug.PrintStack()
g.rwLock.RUnlock()
if g.Max != 0 {
g.reqs <- req{}
}
}
// WriteLock takes a write lock. THis shoudl block until all readers
// are complete
func (g *Governor) WriteLock() {
// debug.PrintStack()
if g.Max != 0 {
for i := 0; i < g.Max; i++ {
_ = <-g.reqs
}
}
g.rwLock.Lock()
}
// WriteUnLock releases the write lock
func (g *Governor) WriteUnLock() (err error) {
// debug.PrintStack()
g.rwLock.Unlock()
if g.Max != 0 {
if len(g.reqs) != 0 {
return errors.New("Tried to unlock when lock not exclusively held")
}
for i := 0; i < g.Max; i++ {
g.reqs <- req{}
}
}
return nil
}