Skip to content

Commit b9d84a9

Browse files
committed
WIP
1 parent 5d11616 commit b9d84a9

File tree

5 files changed

+154
-56
lines changed

5 files changed

+154
-56
lines changed

internal/coord/event.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,9 @@ type EventRoutingPoll struct{}
238238

239239
func (*EventRoutingPoll) behaviourEvent() {}
240240
func (*EventRoutingPoll) routingCommand() {}
241+
242+
type EventStartCrawl struct {
243+
Seed []kadt.PeerID
244+
}
245+
246+
func (*EventStartCrawl) behaviourEvent() {}

internal/coord/routing.go

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ type RoutingBehaviour struct {
303303
explore coordt.StateMachine[routing.ExploreEvent, routing.ExploreState]
304304

305305
// crawl is the state machine that can crawl the network from a set of seed nodes
306-
crawl coordt.StateMachine[routing.ExploreEvent, routing.ExploreState]
306+
crawl coordt.StateMachine[routing.CrawlEvent, routing.CrawlState]
307307

308308
pendingMu sync.Mutex
309309
pending []BehaviourEvent
@@ -374,9 +374,14 @@ func NewRoutingBehaviour(self kadt.PeerID, rt routing.RoutingTableCpl[kadt.Key,
374374
return nil, fmt.Errorf("explore: %w", err)
375375
}
376376

377-
// crawl, err := routing.NewCrawl(self)
377+
crawlCfg := routing.DefaultCrawlConfig()
378378

379-
return ComposeRoutingBehaviour(self, bootstrap, include, probe, explore, cfg)
379+
crawl, err := routing.NewCrawl(self, cplutil.GenRandPeerID, crawlCfg)
380+
if err != nil {
381+
return nil, fmt.Errorf("crawl: %w", err)
382+
}
383+
384+
return ComposeRoutingBehaviour(self, bootstrap, include, probe, explore, crawl, cfg)
380385
}
381386

382387
// ComposeRoutingBehaviour creates a [RoutingBehaviour] composed of the supplied state machines.
@@ -387,6 +392,7 @@ func ComposeRoutingBehaviour(
387392
include coordt.StateMachine[routing.IncludeEvent, routing.IncludeState],
388393
probe coordt.StateMachine[routing.ProbeEvent, routing.ProbeState],
389394
explore coordt.StateMachine[routing.ExploreEvent, routing.ExploreState],
395+
crawl coordt.StateMachine[routing.CrawlEvent, routing.CrawlState],
390396
cfg *RoutingConfig,
391397
) (*RoutingBehaviour, error) {
392398
if cfg == nil {
@@ -402,6 +408,7 @@ func ComposeRoutingBehaviour(
402408
include: include,
403409
probe: probe,
404410
explore: explore,
411+
crawl: crawl,
405412
ready: make(chan struct{}, 1),
406413
}
407414
return r, nil
@@ -418,12 +425,11 @@ func (r *RoutingBehaviour) Notify(ctx context.Context, ev BehaviourEvent) {
418425

419426
// notify must only be called while r.pendingMu is held
420427
func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
421-
ctx, span := r.cfg.Tracer.Start(ctx, "RoutingBehaviour.notify", trace.WithAttributes(attribute.String("event", fmt.Sprintf("%T", ev))))
428+
ctx, span := r.cfg.Tracer.Start(ctx, "RoutingBehaviour.notify", trace.WithAttributes(tele.AttrInEvent(ev)))
422429
defer span.End()
423430

424431
switch ev := ev.(type) {
425432
case *EventStartBootstrap:
426-
span.SetAttributes(attribute.String("event", "EventStartBootstrap"))
427433
cmd := &routing.EventBootstrapStart[kadt.Key, kadt.PeerID]{
428434
KnownClosestNodes: ev.SeedNodes,
429435
}
@@ -433,8 +439,17 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
433439
r.pending = append(r.pending, next)
434440
}
435441

442+
case *EventStartCrawl:
443+
cmd := &routing.EventCrawlStart[kadt.Key, kadt.PeerID]{
444+
Seed: ev.Seed,
445+
}
446+
// attempt to advance the bootstrap
447+
next, ok := r.advanceCrawl(ctx, cmd)
448+
if ok {
449+
r.pending = append(r.pending, next)
450+
}
451+
436452
case *EventAddNode:
437-
span.SetAttributes(attribute.String("event", "EventAddAddrInfo"))
438453
// Ignore self
439454
if r.self.Equal(ev.NodeID) {
440455
break
@@ -450,7 +465,7 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
450465
}
451466

452467
case *EventRoutingUpdated:
453-
span.SetAttributes(attribute.String("event", "EventRoutingUpdated"), attribute.String("nodeid", ev.NodeID.String()))
468+
span.SetAttributes(attribute.String("nodeid", ev.NodeID.String()))
454469
cmd := &routing.EventProbeAdd[kadt.Key, kadt.PeerID]{
455470
NodeID: ev.NodeID,
456471
}
@@ -533,9 +548,23 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
533548
r.pending = append(r.pending, next)
534549
}
535550

551+
case routing.CrawlQueryID:
552+
cmd := &routing.EventCrawlNodeResponse[kadt.Key, kadt.PeerID]{
553+
NodeID: ev.To,
554+
Target: ev.Target,
555+
CloserNodes: ev.CloserNodes,
556+
}
557+
558+
// attempt to advance the crawl
559+
next, ok := r.advanceCrawl(ctx, cmd)
560+
if ok {
561+
r.pending = append(r.pending, next)
562+
}
563+
536564
default:
537565
panic(fmt.Sprintf("unexpected query id: %s", ev.QueryID))
538566
}
567+
539568
case *EventGetCloserNodesFailure:
540569
span.SetAttributes(attribute.String("event", "EventGetCloserNodesFailure"), attribute.String("queryid", string(ev.QueryID)), attribute.String("nodeid", ev.To.String()))
541570
span.RecordError(ev.Err)
@@ -580,10 +609,22 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
580609
if ok {
581610
r.pending = append(r.pending, next)
582611
}
612+
case routing.CrawlQueryID:
613+
cmd := &routing.EventCrawlNodeFailure[kadt.Key, kadt.PeerID]{
614+
NodeID: ev.To,
615+
Target: ev.Target,
616+
Error: ev.Err,
617+
}
618+
// attempt to advance the crawl
619+
next, ok := r.advanceCrawl(ctx, cmd)
620+
if ok {
621+
r.pending = append(r.pending, next)
622+
}
583623

584624
default:
585625
panic(fmt.Sprintf("unexpected query id: %s", ev.QueryID))
586626
}
627+
587628
case *EventNotifyConnectivity:
588629
span.SetAttributes(attribute.String("event", "EventNotifyConnectivity"), attribute.String("nodeid", ev.NodeID.String()))
589630
// ignore self
@@ -609,6 +650,7 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
609650
if ok {
610651
r.pending = append(r.pending, nextProbe)
611652
}
653+
612654
case *EventNotifyNonConnectivity:
613655
span.SetAttributes(attribute.String("event", "EventNotifyConnectivity"), attribute.String("nodeid", ev.NodeID.String()))
614656

@@ -620,6 +662,7 @@ func (r *RoutingBehaviour) notify(ctx context.Context, ev BehaviourEvent) {
620662
if ok {
621663
r.pending = append(r.pending, nextProbe)
622664
}
665+
623666
case *EventRoutingPoll:
624667
r.pollChildren(ctx)
625668

@@ -693,6 +736,11 @@ func (r *RoutingBehaviour) pollChildren(ctx context.Context) {
693736
if ok {
694737
r.pending = append(r.pending, ev)
695738
}
739+
740+
ev, ok = r.advanceCrawl(ctx, &routing.EventCrawlPoll{})
741+
if ok {
742+
r.pending = append(r.pending, ev)
743+
}
696744
}
697745

698746
func (r *RoutingBehaviour) advanceBootstrap(ctx context.Context, ev routing.BootstrapEvent) (BehaviourEvent, bool) {
@@ -817,9 +865,9 @@ func (r *RoutingBehaviour) advanceProbe(ctx context.Context, ev routing.ProbeEve
817865
func (r *RoutingBehaviour) advanceExplore(ctx context.Context, ev routing.ExploreEvent) (BehaviourEvent, bool) {
818866
ctx, span := r.cfg.Tracer.Start(ctx, "RoutingBehaviour.advanceExplore")
819867
defer span.End()
868+
820869
bstate := r.explore.Advance(ctx, ev)
821870
switch st := bstate.(type) {
822-
823871
case *routing.StateExploreFindCloser[kadt.Key, kadt.PeerID]:
824872
r.cfg.Logger.Debug("starting explore", slog.Int("cpl", st.Cpl), tele.LogAttrPeerID(st.NodeID))
825873
return &EventOutboundGetCloserNodes{
@@ -845,3 +893,32 @@ func (r *RoutingBehaviour) advanceExplore(ctx context.Context, ev routing.Explor
845893

846894
return nil, false
847895
}
896+
897+
func (r *RoutingBehaviour) advanceCrawl(ctx context.Context, ev routing.CrawlEvent) (BehaviourEvent, bool) {
898+
ctx, span := r.cfg.Tracer.Start(ctx, "RoutingBehaviour.advanceCrawl")
899+
defer span.End()
900+
901+
cstate := r.crawl.Advance(ctx, ev)
902+
switch st := cstate.(type) {
903+
case *routing.StateCrawlFindCloser[kadt.Key, kadt.PeerID]:
904+
return &EventOutboundGetCloserNodes{
905+
QueryID: routing.CrawlQueryID,
906+
To: st.NodeID,
907+
Target: st.Target,
908+
Notify: r,
909+
}, true
910+
911+
case *routing.StateCrawlWaitingWithCapacity:
912+
// crawl waiting for a message response but has capacity to do more
913+
case *routing.StateCrawlWaitingAtCapacity:
914+
// crawl waiting for a message response but has no capacity to do more
915+
case *routing.StateCrawlFinished:
916+
r.cfg.Logger.Info("crawl finished")
917+
case *routing.StateCrawlIdle:
918+
// bootstrap not running, nothing to do
919+
default:
920+
panic(fmt.Sprintf("unexpected explore state: %T", st))
921+
}
922+
923+
return nil, false
924+
}

internal/coord/routing/crawl.go

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import (
1414
"github.com/plprobelab/zikade/tele"
1515
)
1616

17+
// CrawlQueryID is the id for the query operated by the crawl state machine
18+
const CrawlQueryID = coordt.QueryID("crawl")
19+
1720
// CrawlConfig specifies optional configuration for a Crawl
1821
type CrawlConfig struct {
1922
MaxCPL int // the maximum CPL until we should crawl the peer
@@ -65,7 +68,6 @@ type Crawl[K kad.Key[K], N kad.NodeID[K]] struct {
6568
}
6669

6770
type crawlInformation[K kad.Key[K], N kad.NodeID[K]] struct {
68-
queryID coordt.QueryID
6971
todo []crawlJob[K, N]
7072
cpls map[string]int
7173
waiting map[string]N
@@ -109,7 +111,6 @@ func (c *Crawl[K, N]) Advance(ctx context.Context, ev CrawlEvent) (out CrawlStat
109111
span.SetAttributes(attribute.Int("seed", len(tev.Seed)))
110112

111113
ci := &crawlInformation[K, N]{
112-
queryID: tev.QueryID,
113114
todo: []crawlJob[K, N]{},
114115
cpls: map[string]int{},
115116
waiting: map[string]N{},
@@ -149,9 +150,6 @@ func (c *Crawl[K, N]) Advance(ctx context.Context, ev CrawlEvent) (out CrawlStat
149150

150151
if c.info == nil {
151152
return &StateCrawlIdle{}
152-
} else if c.info.queryID != tev.QueryID {
153-
// if we don't know this query, pretend it was a poll by breaking
154-
break
155153
}
156154

157155
job := crawlJob[K, N]{
@@ -193,9 +191,6 @@ func (c *Crawl[K, N]) Advance(ctx context.Context, ev CrawlEvent) (out CrawlStat
193191
case *EventCrawlNodeFailure[K, N]:
194192
if c.info == nil {
195193
return &StateCrawlIdle{}
196-
} else if c.info.queryID != tev.QueryID {
197-
// if we don't know this query, pretend it was a poll by breaking
198-
break
199194
}
200195

201196
span.RecordError(tev.Error)
@@ -224,9 +219,7 @@ func (c *Crawl[K, N]) Advance(ctx context.Context, ev CrawlEvent) (out CrawlStat
224219
}
225220

226221
if len(c.info.waiting) >= c.cfg.MaxCPL*c.cfg.Concurrency {
227-
return &StateCrawlWaitingAtCapacity{
228-
QueryID: c.info.queryID,
229-
}
222+
return &StateCrawlWaitingAtCapacity{}
230223
}
231224

232225
if len(c.info.todo) > 0 {
@@ -240,16 +233,13 @@ func (c *Crawl[K, N]) Advance(ctx context.Context, ev CrawlEvent) (out CrawlStat
240233
c.info.waiting[mapKey] = job.node
241234

242235
return &StateCrawlFindCloser[K, N]{
243-
QueryID: c.info.queryID,
244-
Target: job.target,
245-
NodeID: job.node,
236+
Target: job.target,
237+
NodeID: job.node,
246238
}
247239
}
248240

249241
if len(c.info.waiting) > 0 {
250-
return &StateCrawlWaitingWithCapacity{
251-
QueryID: c.info.queryID,
252-
}
242+
return &StateCrawlWaitingWithCapacity{}
253243
}
254244

255245
c.info = nil
@@ -291,21 +281,14 @@ type CrawlState interface {
291281

292282
type StateCrawlIdle struct{}
293283

294-
type StateCrawlFinished struct {
295-
QueryID coordt.QueryID
296-
}
284+
type StateCrawlFinished struct{}
297285

298-
type StateCrawlWaitingAtCapacity struct {
299-
QueryID coordt.QueryID
300-
}
301-
type StateCrawlWaitingWithCapacity struct {
302-
QueryID coordt.QueryID
303-
}
286+
type StateCrawlWaitingAtCapacity struct{}
287+
type StateCrawlWaitingWithCapacity struct{}
304288

305289
type StateCrawlFindCloser[K kad.Key[K], N kad.NodeID[K]] struct {
306-
QueryID coordt.QueryID
307-
Target K // the key that the query wants to find closer nodes for
308-
NodeID N // the node to send the message to
290+
Target K // the key that the query wants to find closer nodes for
291+
NodeID N // the node to send the message to
309292
}
310293

311294
// crawlState() ensures that only [Crawl] states can be assigned to a CrawlState.
@@ -325,22 +308,19 @@ type EventCrawlPoll struct{}
325308
// type EventCrawlCancel struct{} // TODO: implement
326309

327310
type EventCrawlStart[K kad.Key[K], N kad.NodeID[K]] struct {
328-
QueryID coordt.QueryID
329-
Seed []N
311+
Seed []N
330312
}
331313

332314
type EventCrawlNodeResponse[K kad.Key[K], N kad.NodeID[K]] struct {
333-
QueryID coordt.QueryID
334315
NodeID N // the node the message was sent to
335316
Target K // the key that the node was asked for
336317
CloserNodes []N // the closer nodes sent by the node
337318
}
338319

339320
type EventCrawlNodeFailure[K kad.Key[K], N kad.NodeID[K]] struct {
340-
QueryID coordt.QueryID
341-
NodeID N // the node the message was sent to
342-
Target K // the key that the node was asked for
343-
Error error // the error that caused the failure, if any
321+
NodeID N // the node the message was sent to
322+
Target K // the key that the node was asked for
323+
Error error // the error that caused the failure, if any
344324
}
345325

346326
// crawlEvent() ensures that only events accepted by [Crawl] can be assigned to a [CrawlEvent].

internal/coord/routing/crawl_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ func TestCrawl_Advance_unrelated_response(t *testing.T) {
305305

306306
// send it an unrelated response
307307
state = qry.Advance(ctx, &EventCrawlNodeResponse[tiny.Key, tiny.Node]{
308-
QueryID: coordt.QueryID("another"),
308+
QueryID: "another",
309309
NodeID: tstate.NodeID,
310310
Target: tstate.Target,
311311
CloserNodes: []tiny.Node{},
@@ -314,7 +314,7 @@ func TestCrawl_Advance_unrelated_response(t *testing.T) {
314314

315315
// send it an unrelated response
316316
state = qry.Advance(ctx, &EventCrawlNodeFailure[tiny.Key, tiny.Node]{
317-
QueryID: coordt.QueryID("another"),
317+
QueryID: "another",
318318
NodeID: tstate.NodeID,
319319
Target: tstate.Target,
320320
Error: fmt.Errorf("some error"),

0 commit comments

Comments
 (0)