always use ReplicationState, and have a map from that to the rsfs
This commit is contained in:
+60
-54
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/bits"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -12,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -type=ReplicationState
|
//go:generate stringer -type=ReplicationState
|
||||||
type ReplicationState int
|
type ReplicationState uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Planning ReplicationState = 1 << iota
|
Planning ReplicationState = 1 << iota
|
||||||
@@ -23,6 +24,22 @@ const (
|
|||||||
ContextDone
|
ContextDone
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s ReplicationState) rsf() replicationStateFunc {
|
||||||
|
idx := bits.TrailingZeros(uint(s))
|
||||||
|
if idx == bits.UintSize {
|
||||||
|
panic(s) // invalid value
|
||||||
|
}
|
||||||
|
m := []replicationStateFunc{
|
||||||
|
rsfPlanning,
|
||||||
|
rsfPlanningError,
|
||||||
|
rsfWorking,
|
||||||
|
rsfWorkingWait,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
return m[idx]
|
||||||
|
}
|
||||||
|
|
||||||
type replicationQueueItem struct {
|
type replicationQueueItem struct {
|
||||||
retriesSinceLastError int
|
retriesSinceLastError int
|
||||||
fsr *FSReplication
|
fsr *FSReplication
|
||||||
@@ -48,7 +65,7 @@ type Replication struct {
|
|||||||
sleepUntil time.Time
|
sleepUntil time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type replicationUpdater func(func(*Replication))
|
type replicationUpdater func(func(*Replication)) (newState ReplicationState)
|
||||||
type replicationStateFunc func(context.Context, EndpointPair, replicationUpdater) replicationStateFunc
|
type replicationStateFunc func(context.Context, EndpointPair, replicationUpdater) replicationStateFunc
|
||||||
|
|
||||||
//go:generate stringer -type=FSReplicationState
|
//go:generate stringer -type=FSReplicationState
|
||||||
@@ -138,25 +155,24 @@ type FSReplicationStep struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Replication) Drive(ctx context.Context, ep EndpointPair, retryNow chan struct{}) {
|
func (r *Replication) Drive(ctx context.Context, ep EndpointPair, retryNow chan struct{}) {
|
||||||
|
|
||||||
var u replicationUpdater = func(f func(*Replication)) {
|
var u replicationUpdater = func(f func(*Replication)) ReplicationState {
|
||||||
r.lock.Lock()
|
r.lock.Lock()
|
||||||
defer r.lock.Unlock()
|
defer r.lock.Unlock()
|
||||||
f(r)
|
if f != nil {
|
||||||
|
f(r)
|
||||||
|
}
|
||||||
|
return r.state
|
||||||
}
|
}
|
||||||
|
|
||||||
var s replicationStateFunc = rsfPlanning
|
var s replicationStateFunc = rsfPlanning
|
||||||
var pre, post ReplicationState
|
var pre, post ReplicationState
|
||||||
for s != nil {
|
for s != nil {
|
||||||
preTime := time.Now()
|
preTime := time.Now()
|
||||||
u(func(r *Replication){
|
pre = u(nil)
|
||||||
pre = r.state
|
|
||||||
})
|
|
||||||
s = s(ctx, ep, u)
|
s = s(ctx, ep, u)
|
||||||
delta := time.Now().Sub(preTime)
|
delta := time.Now().Sub(preTime)
|
||||||
u(func(r *Replication){
|
post = u(nil)
|
||||||
post = r.state
|
|
||||||
})
|
|
||||||
getLogger(ctx).
|
getLogger(ctx).
|
||||||
WithField("transition", fmt.Sprintf("%s => %s", pre, post)).
|
WithField("transition", fmt.Sprintf("%s => %s", pre, post)).
|
||||||
WithField("duration", delta).
|
WithField("duration", delta).
|
||||||
@@ -173,11 +189,10 @@ func rsfPlanning(ctx context.Context, ep EndpointPair, u replicationUpdater) rep
|
|||||||
log := getLogger(ctx)
|
log := getLogger(ctx)
|
||||||
|
|
||||||
handlePlanningError := func(err error) replicationStateFunc {
|
handlePlanningError := func(err error) replicationStateFunc {
|
||||||
u(func(r *Replication){
|
return u(func(r *Replication) {
|
||||||
r.state = PlanningError
|
|
||||||
r.planningError = err
|
r.planningError = err
|
||||||
})
|
r.state = PlanningError
|
||||||
return rsfPlanningError
|
}).rsf()
|
||||||
}
|
}
|
||||||
|
|
||||||
sfss, err := ep.Sender().ListFilesystems(ctx)
|
sfss, err := ep.Sender().ListFilesystems(ctx)
|
||||||
@@ -273,13 +288,12 @@ func rsfPlanning(ctx context.Context, ep EndpointPair, u replicationUpdater) rep
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u(func(r *Replication){
|
return u(func(r *Replication) {
|
||||||
r.completed = completed
|
r.completed = completed
|
||||||
r.pending = pending
|
r.pending = pending
|
||||||
r.state = Working
|
|
||||||
r.planningError = nil
|
r.planningError = nil
|
||||||
})
|
r.state = Working
|
||||||
return rsfWorking
|
}).rsf()
|
||||||
}
|
}
|
||||||
|
|
||||||
func rsfPlanningError(ctx context.Context, ep EndpointPair, u replicationUpdater) replicationStateFunc {
|
func rsfPlanningError(ctx context.Context, ep EndpointPair, u replicationUpdater) replicationStateFunc {
|
||||||
@@ -290,25 +304,23 @@ func rsfPlanningError(ctx context.Context, ep EndpointPair, u replicationUpdater
|
|||||||
t := time.NewTimer(sleepTime) // FIXME make constant onfigurable
|
t := time.NewTimer(sleepTime) // FIXME make constant onfigurable
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
select {
|
select {
|
||||||
case <- ctx.Done():
|
case <-ctx.Done():
|
||||||
u(func(r *Replication){
|
return u(func(r *Replication) {
|
||||||
r.state = ContextDone
|
r.state = ContextDone
|
||||||
r.contextError = ctx.Err()
|
r.contextError = ctx.Err()
|
||||||
})
|
}).rsf()
|
||||||
return nil
|
case <-t.C:
|
||||||
case <- t.C:
|
return u(func(r *Replication) {
|
||||||
u(func(r *Replication){
|
r.state = Planning
|
||||||
r.state = Planning
|
}).rsf()
|
||||||
})
|
|
||||||
return rsfPlanning
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func rsfWorking(ctx context.Context, ep EndpointPair, u replicationUpdater) (rsfNext replicationStateFunc) {
|
func rsfWorking(ctx context.Context, ep EndpointPair, u replicationUpdater) replicationStateFunc {
|
||||||
|
|
||||||
var active *replicationQueueItem
|
var active *replicationQueueItem
|
||||||
|
|
||||||
u(func(r *Replication) {
|
rsfNext := u(func(r *Replication) {
|
||||||
if r.active != nil {
|
if r.active != nil {
|
||||||
active = r.active
|
active = r.active
|
||||||
return
|
return
|
||||||
@@ -349,17 +361,16 @@ func rsfWorking(ctx context.Context, ep EndpointPair, u replicationUpdater) (rsf
|
|||||||
active = r.active
|
active = r.active
|
||||||
r.pending = r.pending[1:]
|
r.pending = r.pending[1:]
|
||||||
|
|
||||||
})
|
}).rsf()
|
||||||
|
|
||||||
if active == nil {
|
if active == nil {
|
||||||
return rsfNext
|
return rsfNext
|
||||||
}
|
}
|
||||||
|
|
||||||
if active.fsr.state == FSRetryWait {
|
if active.fsr.state == FSRetryWait {
|
||||||
u(func(r *Replication) {
|
return u(func(r *Replication) {
|
||||||
r.state = WorkingWait
|
r.state = WorkingWait
|
||||||
})
|
}).rsf()
|
||||||
return rsfWorkingWait
|
|
||||||
}
|
}
|
||||||
if active.fsr.state != FSQueued {
|
if active.fsr.state != FSQueued {
|
||||||
panic(active)
|
panic(active)
|
||||||
@@ -367,7 +378,7 @@ func rsfWorking(ctx context.Context, ep EndpointPair, u replicationUpdater) (rsf
|
|||||||
|
|
||||||
fsState := active.fsr.drive(ctx, ep)
|
fsState := active.fsr.drive(ctx, ep)
|
||||||
|
|
||||||
u(func(r *Replication) {
|
return u(func(r *Replication) {
|
||||||
|
|
||||||
if fsState&FSQueued != 0 {
|
if fsState&FSQueued != 0 {
|
||||||
r.active.retriesSinceLastError = 0
|
r.active.retriesSinceLastError = 0
|
||||||
@@ -380,31 +391,26 @@ func rsfWorking(ctx context.Context, ep EndpointPair, u replicationUpdater) (rsf
|
|||||||
panic(r.active)
|
panic(r.active)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
}).rsf()
|
||||||
|
|
||||||
return rsfWorking
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func rsfWorkingWait(ctx context.Context, ep EndpointPair, u replicationUpdater) replicationStateFunc {
|
func rsfWorkingWait(ctx context.Context, ep EndpointPair, u replicationUpdater) replicationStateFunc {
|
||||||
sleepTime := 10*time.Second
|
sleepTime := 10 * time.Second
|
||||||
u(func(r* Replication){
|
u(func(r *Replication) {
|
||||||
r.sleepUntil = time.Now().Add(sleepTime)
|
r.sleepUntil = time.Now().Add(sleepTime)
|
||||||
})
|
})
|
||||||
t := time.NewTimer(sleepTime)
|
t := time.NewTimer(sleepTime)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
select {
|
select {
|
||||||
case <- ctx.Done():
|
case <-ctx.Done():
|
||||||
u(func(r *Replication){
|
return u(func(r *Replication) {
|
||||||
r.state = ContextDone
|
r.state = ContextDone
|
||||||
r.contextError = ctx.Err()
|
r.contextError = ctx.Err()
|
||||||
})
|
}).rsf()
|
||||||
return nil
|
case <-t.C:
|
||||||
case <- t.C:
|
return u(func(r *Replication) {
|
||||||
u(func(r *Replication){
|
r.state = Working
|
||||||
r.state = Working
|
}).rsf()
|
||||||
})
|
|
||||||
return rsfWorking
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user