mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
compactor: clean up
Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
This commit is contained in:
parent
f7714e269e
commit
7ce69b256a
@ -29,8 +29,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
checkCompactionInterval = 5 * time.Minute
|
|
||||||
|
|
||||||
ModePeriodic = "periodic"
|
ModePeriodic = "periodic"
|
||||||
ModeRevision = "revision"
|
ModeRevision = "revision"
|
||||||
)
|
)
|
||||||
|
@ -46,30 +46,35 @@ type Periodic struct {
|
|||||||
// NewPeriodic creates a new instance of Periodic compactor that purges
|
// NewPeriodic creates a new instance of Periodic compactor that purges
|
||||||
// the log older than h Duration.
|
// the log older than h Duration.
|
||||||
func NewPeriodic(h time.Duration, rg RevGetter, c Compactable) *Periodic {
|
func NewPeriodic(h time.Duration, rg RevGetter, c Compactable) *Periodic {
|
||||||
return &Periodic{
|
return newPeriodic(clockwork.NewRealClock(), h, rg, c)
|
||||||
clock: clockwork.NewRealClock(),
|
}
|
||||||
|
|
||||||
|
func newPeriodic(clock clockwork.Clock, h time.Duration, rg RevGetter, c Compactable) *Periodic {
|
||||||
|
t := &Periodic{
|
||||||
|
clock: clock,
|
||||||
period: h,
|
period: h,
|
||||||
rg: rg,
|
rg: rg,
|
||||||
c: c,
|
c: c,
|
||||||
|
revs: make([]int64, 0),
|
||||||
}
|
}
|
||||||
|
t.ctx, t.cancel = context.WithCancel(context.Background())
|
||||||
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// periodDivisor divides Periodic.period in into checkCompactInterval duration
|
// periodDivisor divides Periodic.period in into checkCompactInterval duration
|
||||||
const periodDivisor = 10
|
const periodDivisor = 10
|
||||||
|
|
||||||
|
// Run runs periodic compactor.
|
||||||
func (t *Periodic) Run() {
|
func (t *Periodic) Run() {
|
||||||
t.ctx, t.cancel = context.WithCancel(context.Background())
|
interval := t.period / time.Duration(periodDivisor)
|
||||||
t.revs = make([]int64, 0)
|
|
||||||
clock := t.clock
|
|
||||||
checkCompactInterval := t.period / time.Duration(periodDivisor)
|
|
||||||
go func() {
|
go func() {
|
||||||
last := clock.Now()
|
initialWait := t.clock.Now()
|
||||||
for {
|
for {
|
||||||
t.revs = append(t.revs, t.rg.Rev())
|
t.revs = append(t.revs, t.rg.Rev())
|
||||||
select {
|
select {
|
||||||
case <-t.ctx.Done():
|
case <-t.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-clock.After(checkCompactInterval):
|
case <-t.clock.After(interval):
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
p := t.paused
|
p := t.paused
|
||||||
t.mu.Unlock()
|
t.mu.Unlock()
|
||||||
@ -77,36 +82,44 @@ func (t *Periodic) Run() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if clock.Now().Sub(last) < t.period {
|
|
||||||
|
// wait up to initial given period
|
||||||
|
if t.clock.Now().Sub(initialWait) < t.period {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rev, remaining := t.getRev()
|
rev, remaining := t.getRev()
|
||||||
if rev < 0 {
|
if rev < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Noticef("Starting auto-compaction at revision %d (retention: %v)", rev, t.period)
|
plog.Noticef("Starting auto-compaction at revision %d (retention: %v)", rev, t.period)
|
||||||
_, err := t.c.Compact(t.ctx, &pb.CompactionRequest{Revision: rev})
|
_, err := t.c.Compact(t.ctx, &pb.CompactionRequest{Revision: rev})
|
||||||
if err == nil || err == mvcc.ErrCompacted {
|
if err == nil || err == mvcc.ErrCompacted {
|
||||||
|
// move to next sliding window
|
||||||
t.revs = remaining
|
t.revs = remaining
|
||||||
plog.Noticef("Finished auto-compaction at revision %d", rev)
|
plog.Noticef("Finished auto-compaction at revision %d", rev)
|
||||||
} else {
|
} else {
|
||||||
plog.Noticef("Failed auto-compaction at revision %d (%v)", rev, err)
|
plog.Noticef("Failed auto-compaction at revision %d (%v)", rev, err)
|
||||||
plog.Noticef("Retry after %v", checkCompactInterval)
|
plog.Noticef("Retry after %v", interval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop stops periodic compactor.
|
||||||
func (t *Periodic) Stop() {
|
func (t *Periodic) Stop() {
|
||||||
t.cancel()
|
t.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pause pauses periodic compactor.
|
||||||
func (t *Periodic) Pause() {
|
func (t *Periodic) Pause() {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
t.paused = true
|
t.paused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resume resumes periodic compactor.
|
||||||
func (t *Periodic) Resume() {
|
func (t *Periodic) Resume() {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
"github.com/coreos/etcd/pkg/testutil"
|
"github.com/coreos/etcd/pkg/testutil"
|
||||||
|
|
||||||
"github.com/jonboulle/clockwork"
|
"github.com/jonboulle/clockwork"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,12 +32,7 @@ func TestPeriodic(t *testing.T) {
|
|||||||
fc := clockwork.NewFakeClock()
|
fc := clockwork.NewFakeClock()
|
||||||
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
||||||
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
||||||
tb := &Periodic{
|
tb := newPeriodic(fc, retentionDuration, rg, compactable)
|
||||||
clock: fc,
|
|
||||||
period: retentionDuration,
|
|
||||||
rg: rg,
|
|
||||||
c: compactable,
|
|
||||||
}
|
|
||||||
|
|
||||||
tb.Run()
|
tb.Run()
|
||||||
defer tb.Stop()
|
defer tb.Stop()
|
||||||
@ -70,15 +66,10 @@ func TestPeriodic(t *testing.T) {
|
|||||||
|
|
||||||
func TestPeriodicPause(t *testing.T) {
|
func TestPeriodicPause(t *testing.T) {
|
||||||
fc := clockwork.NewFakeClock()
|
fc := clockwork.NewFakeClock()
|
||||||
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
|
||||||
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
|
||||||
retentionDuration := time.Hour
|
retentionDuration := time.Hour
|
||||||
tb := &Periodic{
|
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
||||||
clock: fc,
|
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
||||||
period: retentionDuration,
|
tb := newPeriodic(fc, retentionDuration, rg, compactable)
|
||||||
rg: rg,
|
|
||||||
c: compactable,
|
|
||||||
}
|
|
||||||
|
|
||||||
tb.Run()
|
tb.Run()
|
||||||
tb.Pause()
|
tb.Pause()
|
||||||
|
@ -17,6 +17,7 @@ package compactor
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
"github.com/coreos/etcd/mvcc"
|
"github.com/coreos/etcd/mvcc"
|
||||||
@ -43,25 +44,31 @@ type Revision struct {
|
|||||||
// NewRevision creates a new instance of Revisonal compactor that purges
|
// NewRevision creates a new instance of Revisonal compactor that purges
|
||||||
// the log older than retention revisions from the current revision.
|
// the log older than retention revisions from the current revision.
|
||||||
func NewRevision(retention int64, rg RevGetter, c Compactable) *Revision {
|
func NewRevision(retention int64, rg RevGetter, c Compactable) *Revision {
|
||||||
return &Revision{
|
return newRevision(clockwork.NewRealClock(), retention, rg, c)
|
||||||
clock: clockwork.NewRealClock(),
|
}
|
||||||
|
|
||||||
|
func newRevision(clock clockwork.Clock, retention int64, rg RevGetter, c Compactable) *Revision {
|
||||||
|
t := &Revision{
|
||||||
|
clock: clock,
|
||||||
retention: retention,
|
retention: retention,
|
||||||
rg: rg,
|
rg: rg,
|
||||||
c: c,
|
c: c,
|
||||||
}
|
}
|
||||||
|
t.ctx, t.cancel = context.WithCancel(context.Background())
|
||||||
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Revision) Run() {
|
const revInterval = 5 * time.Minute
|
||||||
t.ctx, t.cancel = context.WithCancel(context.Background())
|
|
||||||
clock := t.clock
|
|
||||||
previous := int64(0)
|
|
||||||
|
|
||||||
|
// Run runs revision-based compactor.
|
||||||
|
func (t *Revision) Run() {
|
||||||
|
prev := int64(0)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.ctx.Done():
|
case <-t.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-clock.After(checkCompactionInterval):
|
case <-t.clock.After(revInterval):
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
p := t.paused
|
p := t.paused
|
||||||
t.mu.Unlock()
|
t.mu.Unlock()
|
||||||
@ -71,34 +78,36 @@ func (t *Revision) Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rev := t.rg.Rev() - t.retention
|
rev := t.rg.Rev() - t.retention
|
||||||
|
if rev <= 0 || rev == prev {
|
||||||
if rev <= 0 || rev == previous {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Noticef("Starting auto-compaction at revision %d (retention: %d revisions)", rev, t.retention)
|
plog.Noticef("Starting auto-compaction at revision %d (retention: %d revisions)", rev, t.retention)
|
||||||
_, err := t.c.Compact(t.ctx, &pb.CompactionRequest{Revision: rev})
|
_, err := t.c.Compact(t.ctx, &pb.CompactionRequest{Revision: rev})
|
||||||
if err == nil || err == mvcc.ErrCompacted {
|
if err == nil || err == mvcc.ErrCompacted {
|
||||||
previous = rev
|
prev = rev
|
||||||
plog.Noticef("Finished auto-compaction at revision %d", rev)
|
plog.Noticef("Finished auto-compaction at revision %d", rev)
|
||||||
} else {
|
} else {
|
||||||
plog.Noticef("Failed auto-compaction at revision %d (%v)", rev, err)
|
plog.Noticef("Failed auto-compaction at revision %d (%v)", rev, err)
|
||||||
plog.Noticef("Retry after %v", checkCompactionInterval)
|
plog.Noticef("Retry after %v", revInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop stops revision-based compactor.
|
||||||
func (t *Revision) Stop() {
|
func (t *Revision) Stop() {
|
||||||
t.cancel()
|
t.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pause pauses revision-based compactor.
|
||||||
func (t *Revision) Pause() {
|
func (t *Revision) Pause() {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
t.paused = true
|
t.paused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resume resumes revision-based compactor.
|
||||||
func (t *Revision) Resume() {
|
func (t *Revision) Resume() {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
"github.com/coreos/etcd/pkg/testutil"
|
"github.com/coreos/etcd/pkg/testutil"
|
||||||
|
|
||||||
"github.com/jonboulle/clockwork"
|
"github.com/jonboulle/clockwork"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,23 +29,18 @@ func TestRevision(t *testing.T) {
|
|||||||
fc := clockwork.NewFakeClock()
|
fc := clockwork.NewFakeClock()
|
||||||
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
rg := &fakeRevGetter{testutil.NewRecorderStream(), 0}
|
||||||
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
||||||
tb := &Revision{
|
tb := newRevision(fc, 10, rg, compactable)
|
||||||
clock: fc,
|
|
||||||
retention: 10,
|
|
||||||
rg: rg,
|
|
||||||
c: compactable,
|
|
||||||
}
|
|
||||||
|
|
||||||
tb.Run()
|
tb.Run()
|
||||||
defer tb.Stop()
|
defer tb.Stop()
|
||||||
|
|
||||||
fc.Advance(checkCompactionInterval)
|
fc.Advance(revInterval)
|
||||||
rg.Wait(1)
|
rg.Wait(1)
|
||||||
// nothing happens
|
// nothing happens
|
||||||
|
|
||||||
rg.SetRev(99) // will be 100
|
rg.SetRev(99) // will be 100
|
||||||
expectedRevision := int64(90)
|
expectedRevision := int64(90)
|
||||||
fc.Advance(checkCompactionInterval)
|
fc.Advance(revInterval)
|
||||||
rg.Wait(1)
|
rg.Wait(1)
|
||||||
a, err := compactable.Wait(1)
|
a, err := compactable.Wait(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -61,7 +57,7 @@ func TestRevision(t *testing.T) {
|
|||||||
|
|
||||||
rg.SetRev(199) // will be 200
|
rg.SetRev(199) // will be 200
|
||||||
expectedRevision = int64(190)
|
expectedRevision = int64(190)
|
||||||
fc.Advance(checkCompactionInterval)
|
fc.Advance(revInterval)
|
||||||
rg.Wait(1)
|
rg.Wait(1)
|
||||||
a, err = compactable.Wait(1)
|
a, err = compactable.Wait(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -74,22 +70,17 @@ func TestRevision(t *testing.T) {
|
|||||||
|
|
||||||
func TestRevisionPause(t *testing.T) {
|
func TestRevisionPause(t *testing.T) {
|
||||||
fc := clockwork.NewFakeClock()
|
fc := clockwork.NewFakeClock()
|
||||||
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
|
||||||
rg := &fakeRevGetter{testutil.NewRecorderStream(), 99} // will be 100
|
rg := &fakeRevGetter{testutil.NewRecorderStream(), 99} // will be 100
|
||||||
tb := &Revision{
|
compactable := &fakeCompactable{testutil.NewRecorderStream()}
|
||||||
clock: fc,
|
tb := newRevision(fc, 10, rg, compactable)
|
||||||
retention: 10,
|
|
||||||
rg: rg,
|
|
||||||
c: compactable,
|
|
||||||
}
|
|
||||||
|
|
||||||
tb.Run()
|
tb.Run()
|
||||||
tb.Pause()
|
tb.Pause()
|
||||||
|
|
||||||
// tb will collect 3 hours of revisions but not compact since paused
|
// tb will collect 3 hours of revisions but not compact since paused
|
||||||
n := int(time.Hour / checkCompactionInterval)
|
n := int(time.Hour / revInterval)
|
||||||
for i := 0; i < 3*n; i++ {
|
for i := 0; i < 3*n; i++ {
|
||||||
fc.Advance(checkCompactionInterval)
|
fc.Advance(revInterval)
|
||||||
}
|
}
|
||||||
// tb ends up waiting for the clock
|
// tb ends up waiting for the clock
|
||||||
|
|
||||||
@ -103,7 +94,7 @@ func TestRevisionPause(t *testing.T) {
|
|||||||
tb.Resume()
|
tb.Resume()
|
||||||
|
|
||||||
// unblock clock, will kick off a compaction at hour 3:05
|
// unblock clock, will kick off a compaction at hour 3:05
|
||||||
fc.Advance(checkCompactionInterval)
|
fc.Advance(revInterval)
|
||||||
rg.Wait(1)
|
rg.Wait(1)
|
||||||
a, err := compactable.Wait(1)
|
a, err := compactable.Wait(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user