action_move_group.go ×11

Frontier kind: Joint frontier

unlabeled · c_5152ba56dacb

1 test · 5586 LOC · 212 files · introduces 1 test · 84 LOC · 5 files

Introduces — evidence that enters the hierarchy at this concept

Code
16 ranges84 lines · 5 files
Tests
1 test

Contains — complete concept membership

All code (extent)
979 ranges5586 lines · 212 files · Browse complete extent
All tests (intent)
1 testBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

1 test introduced at this concept.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

5 files ranked by introduced lines: 84 introduced LOC across 16 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

go.temporal.io/server/service/history/queues/action_move_group.go 66 introduced LOC · 11 ranges

Open complete file

20 moveGroupTaskCountMultiplier float64,
21 logger log.Logger,
22 > ) *actionMoveGroup { action_move_group.go
23 > return &actionMoveGroup{
24 > maxReaderCount: maxReaderCount,
25 > grouper: grouper,
26 > moveGroupTaskCountBase: moveGroupTaskCountBase,
27 > moveGroupTaskCountMultiplier: moveGroupTaskCountMultiplier,
28 > logger: logger,
29 > }
30 > }
31
32 > func (a *actionMoveGroup) Name() string { action_move_group.go
33 > return "move-group"
34 > }
35
36 > func (a *actionMoveGroup) Run(readerGroup *ReaderGroup) bool { action_move_group.go
37 >
38 > // Move task groups from reader x to x+1 if the # of pending tasks for a group is higher than
39 > // a threshold. The threshold is calculated as:
40 > // moveGroupTaskCountBase * (moveGroupTaskCountMultiplier ^ x)
41 > //
42 > // If after moving a group to reader x+1, the # of pending tasks for that group becomes higher than
43 > // the threshold for reader x+1, it will be moved to reader x+2 in the next iteration.
44 >
45 > // TODO: instead of moving task groups down by just one reader, directly move it to the reader level
46 > // based on the total number of pending tasks across all readers.
47 >
48 > moved := false
49 > moveGroupMinTaskCount := a.moveGroupTaskCountBase
50 > for readerID := DefaultReaderId; readerID+1 < int64(a.maxReaderCount); readerID++ {
51 > if readerID != DefaultReaderId {
52 > moveGroupMinTaskCount = int(float64(moveGroupMinTaskCount) * a.moveGroupTaskCountMultiplier)
53 > }
54
55 > reader, ok := readerGroup.ReaderByID(readerID) action_move_group.go
56 > if !ok {
57 continue
58 }
59
60 > pendingTaskPerGroup := make(map[any]int) action_move_group.go
61 > reader.WalkSlices(func(s Slice) {
62 > for key, pendingTaskCount := range s.TaskStats().PendingPerKey {
63 > pendingTaskPerGroup[key] += pendingTaskCount
64 > }
65 })
66
67 > groupsToMove := make([]any, 0, len(pendingTaskPerGroup)) action_move_group.go
68 > for key, pendingTaskCount := range pendingTaskPerGroup {
69 > if pendingTaskCount >= moveGroupMinTaskCount {
70 > groupsToMove = append(groupsToMove, key)
71 > a.logger.Info("Too many pending tasks, moving group to next reader",
72 > tag.QueueReaderID(readerID),
73 > tag.Counter(pendingTaskCount),
74 > tag.Value(key),
75 > )
76 > }
77 }
78
79 > if len(groupsToMove) == 0 { action_move_group.go
80 continue
81 }
82
83 > predicateForSplit := a.grouper.Predicate(groupsToMove) action_move_group.go
84 >
85 > var slicesToMove []Slice
86 > reader.SplitSlices(func(s Slice) ([]Slice, bool) {
87 > // Technically we don't need this empty scope check, but it helps avoid
88 > // unnecessary allocation and task movement.
89 > scope := s.Scope()
90 > splitScope, _ := scope.SplitByPredicate(predicateForSplit)
91 > if splitScope.IsEmpty() {
92 > return nil, false
93 > }
94
95 > split, remain := s.SplitByPredicate(predicateForSplit) action_move_group.go
96 > slicesToMove = append(slicesToMove, split)
97 > return []Slice{remain}, true
98 })
99
100 > nextReader := readerGroup.GetOrCreateReader(readerID + 1) action_move_group.go
101 > nextReader.MergeSlices(slicesToMove...)
102 > moved = true
103 }
104
105 > return moved action_move_group.go
106 }
go.temporal.io/server/service/history/queues/slice.go 7 introduced LOC · 1 range

Open complete file

412 }
413
414 > func (s *SliceImpl) TaskStats() TaskStats { slice.go
415 > s.stateSanityCheck()
416 >
417 > return TaskStats{
418 > PendingPerKey: s.pendingPerKey,
419 > }
420 > }
421
422 func (s *SliceImpl) Clear() {
go.temporal.io/server/service/history/queues/reader.go 5 introduced LOC · 2 ranges

Open complete file

251 currentSliceElement = currentSliceElement.Next()
252 } else {
253 > mergeOrAppendSlice(mergedSlices, incomingSlice) reader.go
254 > incomingSliceIdx++
255 > }
256 }
257
258 for ; currentSliceElement != nil; currentSliceElement = currentSliceElement.Next() {
259 > mergeOrAppendSlice(mergedSlices, currentSliceElement.Value.(Slice)) reader.go
260 > }
261 for _, slice := range incomingSlices[incomingSliceIdx:] {
262 mergeOrAppendSlice(mergedSlices, slice)
go.temporal.io/server/service/history/queues/queue_base.go 4 introduced LOC · 1 range

Open complete file

302 maxReaderCount := p.options.MaxReaderCount()
303 if taskCountBase := p.options.MoveGroupTaskCountBase(); taskCountBase > 0 {
304 > // Run an action to proactively move task group with high pending task to non-default reader queue_base.go
305 > // so that upon shard reload, those groups won't block other tasks in the default reader from
306 > // being loaded.
307 > checkpointAction = newMoveGroupAction(maxReaderCount, p.grouper, taskCountBase, p.options.MoveGroupTaskCountMultiplier(), p.logger)
308 } else {
309 // Run slicePredicateAction to move slices with non-universal predicate to non-default reader
go.temporal.io/server/service/history/queues/reader_group.go 2 introduced LOC · 1 range

Open complete file

94 reader, ok := g.getReaderByIDLocked(readerID)
95 if ok {
96 > return reader reader_group.go
97 > }
98
99 return g.newReaderLocked(readerID)