swarm/storage/feed/lookup: LE hint check if main lookup fails

This commit is contained in:
Javier Peletier 2019-04-04 16:23:15 +02:00
parent 78bf51827b
commit d378227c95

View file

@ -28,6 +28,10 @@ var LongEarthLookbackDelay = 250 * time.Millisecond
// timeout is the maximum execution time of the passed `read` function. // timeout is the maximum execution time of the passed `read` function.
// the two head starts can be configured by changing LongEarthLookaheadDelay or LongEarthLookbackDelay // the two head starts can be configured by changing LongEarthLookaheadDelay or LongEarthLookbackDelay
func LongEarthAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFunc) (interface{}, error) { func LongEarthAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFunc) (interface{}, error) {
if hint == NoClue {
hint = worstHint
}
var stepCounter int32 // for debugging, stepCounter allows to give an ID to each step instance var stepCounter int32 // for debugging, stepCounter allows to give an ID to each step instance
errc := make(chan struct{}) // errc will help as an error shortcut signal errc := make(chan struct{}) // errc will help as an error shortcut signal
@ -58,25 +62,6 @@ func LongEarthAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFu
// define the lookBack function, which will follow the path as if R was unsuccessful // define the lookBack function, which will follow the path as if R was unsuccessful
lookBack := func() { lookBack := func() {
if epoch.Base() == hint.Base() { if epoch.Base() == hint.Base() {
// we have reached the hint itself
if hint == worstHint {
valueB = nil
return
}
var err error
// check the hint. If successful, this is it. Otherwise
// we've been given a bad hint!
valueB, err = read(ctxB, hint, now)
if valueB != nil || err == context.Canceled {
return
}
if err != nil {
gerr = err
close(errc)
return
}
// bad hint.
valueB = step(ctxB, hint.Base(), worstHint)
return return
} }
base := epoch.Base() base := epoch.Base()
@ -154,19 +139,40 @@ func LongEarthAlgorithm(ctx context.Context, now uint64, hint Epoch, read ReadFu
var value interface{} var value interface{}
stepCtx, cancel := context.WithCancel(ctx) stepCtx, cancel := context.WithCancel(ctx)
defer cancel()
go func() { // launch the root step in its own goroutine to allow cancellation go func() { // launch the root step in its own goroutine to allow cancellation
defer cancel()
value = step(stepCtx, now, hint) value = step(stepCtx, now, hint)
cancel()
}() }()
// wait for the algorithm to finish, but shortcut in case // wait for the algorithm to finish, but shortcut in case
// of errors // of errors
select { select {
case <-stepCtx.Done(): case <-stepCtx.Done():
return value, ctx.Err()
case <-errc: case <-errc:
cancel()
return nil, gerr return nil, gerr
} }
if ctx.Err() != nil {
return nil, ctx.Err()
}
if value != nil || hint == worstHint {
return value, nil
}
value, err := read(ctx, hint, now)
if err != nil {
return nil, err
}
if value != nil {
return value, nil
}
now = hint.Base()
if hint.Level == HighestLevel {
now--
}
return LongEarthAlgorithm(ctx, now, NoClue, read)
} }