@@ -61,81 +61,85 @@ func newPeriodic(clock clockwork.Clock, h time.Duration, rg RevGetter, c Compact
61
61
return t
62
62
}
63
63
64
+ /*
65
+ Compaction period 1-hour:
66
+ 1. compute compaction period, which is 1-hour
67
+ 2. record revisions for every 1/10 of 1-hour (6-minute)
68
+ 3. keep recording revisions with no compaction for first 1-hour
69
+ 4. do compact with revs[0]
70
+ - success? contiue on for-loop and move sliding window; revs = revs[1:]
71
+ - failure? update revs, and retry after 1/10 of 1-hour (6-minute)
72
+
73
+ Compaction period 24-hour:
74
+ 1. compute compaction period, which is 1-hour
75
+ 2. record revisions for every 1/10 of 1-hour (6-minute)
76
+ 3. keep recording revisions with no compaction for first 24-hour
77
+ 4. do compact with revs[0]
78
+ - success? contiue on for-loop and move sliding window; revs = revs[1:]
79
+ - failure? update revs, and retry after 1/10 of 1-hour (6-minute)
80
+
81
+ Compaction period 59-min:
82
+ 1. compute compaction period, which is 59-min
83
+ 2. record revisions for every 1/10 of 59-min (5.9-min)
84
+ 3. keep recording revisions with no compaction for first 59-min
85
+ 4. do compact with revs[0]
86
+ - success? contiue on for-loop and move sliding window; revs = revs[1:]
87
+ - failure? update revs, and retry after 1/10 of 59-min (5.9-min)
88
+
89
+ Compaction period 5-sec:
90
+ 1. compute compaction period, which is 5-sec
91
+ 2. record revisions for every 1/10 of 5-sec (0.5-sec)
92
+ 3. keep recording revisions with no compaction for first 5-sec
93
+ 4. do compact with revs[0]
94
+ - success? contiue on for-loop and move sliding window; revs = revs[1:]
95
+ - failure? update revs, and retry after 1/10 of 5-sec (0.5-sec)
96
+ */
97
+
98
+ // Run runs periodic compactor.
64
99
func (t * Periodic ) Run () {
65
- fetchInterval := t .getFetchInterval ()
100
+ compactInterval := t .getCompactInterval ()
66
101
retryInterval := t .getRetryInterval ()
67
- retentions := int (t .period / fetchInterval ) + 1 // number of revs to keep for t.period
68
- notify := make (chan struct {}, 1 )
102
+ retentions := t .getRetentions ()
69
103
70
- // periodically updates t.revs and notify to the other goroutine
71
104
go func () {
105
+ lastSuccess := t .clock .Now ()
106
+ baseInterval := t .period
72
107
for {
73
- rev := t .rg .Rev ()
74
- t .mu .Lock ()
75
- t .revs = append (t .revs , rev )
108
+ t .revs = append (t .revs , t .rg .Rev ())
76
109
if len (t .revs ) > retentions {
77
110
t .revs = t .revs [1 :] // t.revs[0] is always the rev at t.period ago
78
111
}
79
- t .mu .Unlock ()
80
-
81
- select {
82
- case notify <- struct {}{}:
83
- default :
84
- // compaction can take time more than interval
85
- }
86
112
87
113
select {
88
114
case <- t .ctx .Done ():
89
115
return
90
- case <- t .clock .After (fetchInterval ):
91
- }
92
- }
93
- }()
94
-
95
- // run compaction triggered by the other goroutine thorough the notify channel
96
- // or internal periodic retry
97
- go func () {
98
- var lastCompactedRev int64
99
- for {
100
- select {
101
- case <- t .ctx .Done ():
102
- return
103
- case <- notify :
104
- // from the other goroutine
105
116
case <- t .clock .After (retryInterval ):
106
- // for retry
107
- // when t.rev is not updated, this event will be ignored later,
108
- // so we don't need to think about race with <-notify.
117
+ t .mu .Lock ()
118
+ p := t .paused
119
+ t .mu .Unlock ()
120
+ if p {
121
+ continue
122
+ }
109
123
}
110
124
111
- t .mu .Lock ()
112
- p := t .paused
113
- rev := t .revs [0 ]
114
- len := len (t .revs )
115
- t .mu .Unlock ()
116
- if p {
125
+ if t .clock .Now ().Sub (lastSuccess ) < baseInterval {
117
126
continue
118
127
}
119
128
120
- // it's too early to start working
121
- if len != retentions {
122
- continue
123
- }
124
-
125
- // if t.revs is not updated, we can ignore the event.
126
- // it's not the first time to try comapction in this interval.
127
- if rev == lastCompactedRev {
128
- continue
129
+ // wait up to initial given period
130
+ if baseInterval == t .period {
131
+ baseInterval = compactInterval
129
132
}
133
+ rev := t .revs [0 ]
130
134
131
135
plog .Noticef ("Starting auto-compaction at revision %d (retention: %v)" , rev , t .period )
132
136
_ , err := t .c .Compact (t .ctx , & pb.CompactionRequest {Revision : rev })
133
137
if err == nil || err == mvcc .ErrCompacted {
138
+ lastSuccess = t .clock .Now ()
134
139
plog .Noticef ("Finished auto-compaction at revision %d" , rev )
135
- lastCompactedRev = rev
136
140
} else {
137
141
plog .Noticef ("Failed auto-compaction at revision %d (%v)" , rev , err )
138
- plog .Noticef ("Retry after %s " , retryInterval )
142
+ plog .Noticef ("Retry after %v " , retryInterval )
139
143
}
140
144
}
141
145
}()
@@ -145,43 +149,41 @@ func (t *Periodic) Run() {
145
149
// (e.g. --auto-compaction-mode 'periodic' --auto-compaction-retention='10m', then compact every 10-minute)
146
150
// if given compaction period x is >1-hour, compact every hour.
147
151
// (e.g. --auto-compaction-mode 'periodic' --auto-compaction-retention='2h', then compact every 1-hour)
148
- func (t * Periodic ) getFetchInterval () time.Duration {
152
+ func (t * Periodic ) getCompactInterval () time.Duration {
149
153
itv := t .period
150
154
if itv > time .Hour {
151
155
itv = time .Hour
152
156
}
153
157
return itv
154
158
}
155
159
160
+ func (t * Periodic ) getRetentions () int {
161
+ return int (t .period / t .getRetryInterval ())
162
+ }
163
+
156
164
const retryDivisor = 10
157
165
158
166
func (t * Periodic ) getRetryInterval () time.Duration {
159
- itv := t .period / retryDivisor
160
- // we don't want to too aggressive retries
161
- // and also jump between 6-minute through 60-minute
162
- if itv < (6 * time .Minute ) { // t.period is less than hour
163
- // if t.period is less than 6-minute,
164
- // retry interval is t.period.
165
- // if we divide byretryDivisor, it's too aggressive
166
- if t .period < 6 * time .Minute {
167
- itv = t .period
168
- } else {
169
- itv = 6 * time .Minute
170
- }
167
+ itv := t .period
168
+ if itv > time .Hour {
169
+ itv = time .Hour
171
170
}
172
- return itv
171
+ return itv / retryDivisor
173
172
}
174
173
174
+ // Stop stops periodic compactor.
175
175
func (t * Periodic ) Stop () {
176
176
t .cancel ()
177
177
}
178
178
179
+ // Pause pauses periodic compactor.
179
180
func (t * Periodic ) Pause () {
180
181
t .mu .Lock ()
181
182
defer t .mu .Unlock ()
182
183
t .paused = true
183
184
}
184
185
186
+ // Resume resumes periodic compactor.
185
187
func (t * Periodic ) Resume () {
186
188
t .mu .Lock ()
187
189
defer t .mu .Unlock ()
0 commit comments