1
1
package plan_fragments
2
2
3
- import "github.com/thanos-io/promql-engine/logicalplan"
3
+ import (
4
+ "encoding/binary"
5
+
6
+ "github.com/google/uuid"
7
+ "github.com/thanos-io/promql-engine/logicalplan"
8
+
9
+ "github.com/cortexproject/cortex/pkg/distributed_execution"
10
+ )
4
11
5
12
// Fragmenter interface
6
13
type Fragmenter interface {
7
14
// Fragment function fragments the logical query plan and will always return the fragment in the order of child-to-root
8
15
// in other words, the order of the fragment in the array will be the order they are being scheduled
9
- Fragment (node logicalplan.Node ) ([]Fragment , error )
16
+ Fragment (queryID uint64 , node logicalplan.Node ) ([]Fragment , error )
10
17
}
11
18
12
- type DummyFragmenter struct {
19
+ func getNewID () uint64 {
20
+ id := uuid .New ()
21
+ return binary .BigEndian .Uint64 (id [:8 ])
13
22
}
14
23
15
- func (f * DummyFragmenter ) Fragment (node logicalplan.Node ) ([]Fragment , error ) {
16
- // simple logic without distributed optimizer
17
- return []Fragment {
18
- {
24
+ type PlanFragmenter struct {
25
+ }
26
+
27
+ func (f * PlanFragmenter ) Fragment (queryID uint64 , node logicalplan.Node ) ([]Fragment , error ) {
28
+ fragments := []Fragment {}
29
+
30
+ nodeToFragmentID := make (map [* logicalplan.Node ]uint64 )
31
+ nodeToSubtreeFragmentIDs := make (map [* logicalplan.Node ][]uint64 )
32
+
33
+ logicalplan .TraverseBottomUp (nil , & node , func (parent , current * logicalplan.Node ) bool {
34
+ childFragmentIDs := make (map [uint64 ]bool )
35
+ children := (* current ).Children ()
36
+
37
+ for _ , child := range children {
38
+ if subtreeIDs , exists := nodeToSubtreeFragmentIDs [child ]; exists {
39
+ for _ , fragmentID := range subtreeIDs {
40
+ childFragmentIDs [fragmentID ] = true
41
+ }
42
+ }
43
+ }
44
+
45
+ childIDs := make ([]uint64 , 0 , len (childFragmentIDs ))
46
+ for fragmentID := range childFragmentIDs {
47
+ childIDs = append (childIDs , fragmentID )
48
+ }
49
+
50
+ if parent == nil { // root fragment
51
+ newFragment := Fragment {
52
+ Node : * current ,
53
+ FragmentID : getNewID (),
54
+ ChildIDs : childIDs ,
55
+ IsRoot : true ,
56
+ }
57
+ fragments = append (fragments , newFragment )
58
+
59
+ // cache subtree fragment IDs for this node
60
+ nodeToSubtreeFragmentIDs [current ] = childIDs
61
+
62
+ } else if distributed_execution .RemoteNode == (* current ).Type () {
63
+ remoteNode := (* current ).(* distributed_execution.Remote )
64
+ fragmentID := getNewID ()
65
+ nodeToFragmentID [current ] = fragmentID
66
+
67
+ // Set the fragment key for the remote node
68
+ key := distributed_execution .MakeFragmentKey (queryID , fragmentID )
69
+ remoteNode .FragmentKey = key
70
+
71
+ newFragment := Fragment {
72
+ Node : remoteNode .Expr ,
73
+ FragmentID : fragmentID ,
74
+ ChildIDs : childIDs ,
75
+ IsRoot : false ,
76
+ }
77
+
78
+ fragments = append (fragments , newFragment )
79
+
80
+ subtreeIDs := append ([]uint64 {fragmentID }, childIDs ... )
81
+ nodeToSubtreeFragmentIDs [current ] = subtreeIDs
82
+ } else {
83
+ nodeToSubtreeFragmentIDs [current ] = childIDs
84
+ }
85
+
86
+ return false
87
+ })
88
+
89
+ if len (fragments ) > 0 {
90
+ return fragments , nil
91
+ } else {
92
+ // for non-query API calls
93
+ // --> treat as root fragment and immediately return the result
94
+ return []Fragment {{
19
95
Node : node ,
20
- FragmentID : uint64 (1 ),
96
+ FragmentID : uint64 (0 ),
21
97
ChildIDs : []uint64 {},
22
98
IsRoot : true ,
23
- },
24
- }, nil
99
+ }}, nil
100
+ }
25
101
}
26
102
27
103
type Fragment struct {
@@ -47,6 +123,6 @@ func (s *Fragment) IsEmpty() bool {
47
123
return true
48
124
}
49
125
50
- func NewDummyFragmenter () Fragmenter {
51
- return & DummyFragmenter {}
126
+ func NewPlanFragmenter () Fragmenter {
127
+ return & PlanFragmenter {}
52
128
}
0 commit comments