/
template.go
127 lines (100 loc) · 2.82 KB
/
template.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package templates
import (
"context"
"sync"
"time"
"github.com/allaboutapps/integresql/pkg/db"
"github.com/allaboutapps/integresql/pkg/util"
)
type TemplateState int32
const (
TemplateStateInit TemplateState = iota
TemplateStateDiscarded
TemplateStateFinalized
)
type Template struct {
TemplateConfig
db.Database
state TemplateState
cond *sync.Cond
mutex sync.RWMutex
}
type TemplateConfig struct {
db.DatabaseConfig
}
func NewTemplate(hash string, config TemplateConfig) *Template {
t := &Template{
TemplateConfig: config,
Database: db.Database{TemplateHash: hash, Config: config.DatabaseConfig},
state: TemplateStateInit,
}
t.cond = sync.NewCond(&t.mutex)
return t
}
func (t *Template) GetConfig(_ context.Context) TemplateConfig {
t.mutex.RLock()
defer t.mutex.RUnlock()
return t.TemplateConfig
}
// GetState locks the template and checks its state.
func (t *Template) GetState(_ context.Context) TemplateState {
t.mutex.RLock()
defer t.mutex.RUnlock()
return t.state
}
// SetState sets the desired state and broadcasts the change to whoever is waiting for it.
func (t *Template) SetState(ctx context.Context, newState TemplateState) {
if t.GetState(ctx) == newState {
return
}
t.mutex.Lock()
defer t.mutex.Unlock()
t.state = newState
t.cond.Broadcast()
}
// WaitUntilFinalized checks the current template state and returns directly if it's 'Finalized'.
// If it's not, the function waits the given timeout until the template state changes.
// On timeout, the old state is returned, otherwise - the new state.
func (t *Template) WaitUntilFinalized(ctx context.Context, timeout time.Duration) (exitState TemplateState) {
currentState := t.GetState(ctx)
if currentState == TemplateStateFinalized {
return currentState
}
newState, err := util.WaitWithTimeout(ctx, timeout, func(context.Context) (TemplateState, error) {
t.cond.L.Lock()
defer t.cond.L.Unlock()
t.cond.Wait()
return t.state, nil
})
if err != nil {
return currentState
}
return newState
}
// GetStateWithLock gets the current state leaving the template locked.
// REMEMBER to unlock it when you no longer need it locked.
func (t *Template) GetStateWithLock(_ context.Context) (TemplateState, LockedTemplate) {
t.mutex.Lock()
return t.state, LockedTemplate{t: t}
}
type LockedTemplate struct {
t *Template
}
// Unlock releases the locked template.
func (l *LockedTemplate) Unlock() {
if l.t != nil {
l.t.mutex.Unlock()
l.t = nil
}
}
// SetState sets a new state of the locked template (without acquiring the lock again).
func (l LockedTemplate) SetState(_ context.Context, newState TemplateState) {
if l.t.state == newState {
return
}
l.t.state = newState
l.t.cond.Broadcast()
}
func (c TemplateConfig) Equals(other TemplateConfig) bool {
return c.DatabaseConfig.ConnectionString() == other.ConnectionString()
}