github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/disttae/route/route.go (about) 1 // Copyright 2021 -2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package route 16 17 import ( 18 "strings" 19 20 "github.com/matrixorigin/matrixone/pkg/clusterservice" 21 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 22 ) 23 24 // RouteForSuperTenant is used to select CN servers for sys tenant. 25 // For sys tenant, there are some special strategies to select CN servers. 26 // First of all, the requested labels must be match with the ones on servers. 27 // Then, the following strategies are listed in order of priority: 28 // 1. The CN servers which are configured as sys account. 29 // 2. The CN servers which are configured as some labels whose key is not account. 30 // 3. The CN servers which are configured as no labels. 31 // 4. At last, if no CN servers are selected, 32 // 4.1 If the username is dump or root, we just select one randomly. 33 // 4.2 Else, no servers are selected. 34 func RouteForSuperTenant( 35 selector clusterservice.Selector, 36 username string, 37 filter func(string) bool, 38 appendFn func(service *metadata.CNService), 39 ) { 40 mc := clusterservice.GetMOCluster() 41 42 // found is true indicates that we have find some available CN services. 43 var found bool 44 var emptyCNs []*metadata.CNService 45 46 // S1: Select servers that configured as sys account. 47 mc.GetCNService(selector, func(s metadata.CNService) bool { 48 if filter != nil && filter(s.SQLAddress) { 49 return true 50 } 51 // At this phase, only append non-empty servers. 52 if len(s.Labels) == 0 { 53 emptyCNs = append(emptyCNs, &s) 54 } else { 55 found = true 56 appendFn(&s) 57 } 58 return true 59 }) 60 if found { 61 return 62 } 63 64 // S2: If there are no servers that are configured as sys account. 65 // There may be some performance issues, but we need to do this still. 66 // (1) If there is only one request label, which is account:sys, we fetch all 67 // CN servers. 68 // (2) Otherwise, there are other labels, we fetch the CN servers whose labels 69 // are matched with them. 70 // In the apply function, we only append the CN servers who has no account key, 71 // to filter out the CN servers who belongs to some common tenants. 72 var se clusterservice.Selector 73 if selector.LabelNum() == 1 { 74 se = clusterservice.NewSelector() 75 } else { 76 se = selector.SelectWithoutLabel(map[string]string{"account": "sys"}) 77 } 78 mc.GetCNService(se, func(s metadata.CNService) bool { 79 if filter != nil && filter(s.SQLAddress) { 80 return true 81 } 82 // Append CN servers that are not configured as label with key "account". 83 if _, ok := s.Labels["account"]; len(s.Labels) > 0 && !ok { 84 found = true 85 appendFn(&s) 86 } 87 return true 88 }) 89 if found { 90 return 91 } 92 93 // S3: Select CN servers which has no labels. 94 if len(emptyCNs) > 0 { 95 for _, cn := range emptyCNs { 96 appendFn(cn) 97 } 98 return 99 } 100 101 // S4.1: If the root is super, return all servers. 102 username = strings.ToLower(username) 103 if username == "dump" || username == "root" { 104 mc.GetCNService(clusterservice.NewSelector(), func(s metadata.CNService) bool { 105 if filter != nil && filter(s.SQLAddress) { 106 return true 107 } 108 appendFn(&s) 109 return true 110 }) 111 return 112 } 113 114 // S4.2: No servers are returned. 115 } 116 117 // RouteForCommonTenant selects CN services for common tenant. 118 // If there are CN services for the selector, just select them, 119 // else, return CN services with empty labels if there are any. 120 func RouteForCommonTenant( 121 selector clusterservice.Selector, filter func(string) bool, appendFn func(service *metadata.CNService), 122 ) { 123 mc := clusterservice.GetMOCluster() 124 125 // found is true indicates that there are CN services for the selector. 126 var found bool 127 128 // preEmptyCNs keeps the CN services that has empty labels before we 129 // find any CN service with non-empty label. 130 var preEmptyCNs []*metadata.CNService 131 132 mc.GetCNService(selector, func(s metadata.CNService) bool { 133 if filter != nil && filter(s.SQLAddress) { 134 return true 135 } 136 if len(s.Labels) > 0 { 137 // Find available CN, append it. 138 found = true 139 appendFn(&s) 140 } else { 141 if found { 142 // If there are already CN services with non-empty labels, 143 // then ignore those with empty labels. 144 return true 145 } else { 146 // If there are no CN services with non-empty labels yet, 147 // save the CNs to preEmptyCNs first. 148 preEmptyCNs = append(preEmptyCNs, &s) 149 return true 150 } 151 } 152 return true 153 }) 154 155 // If there are no CN services with non-empty labels, 156 // return those with empty labels. 157 if !found && len(preEmptyCNs) > 0 { 158 for _, cn := range preEmptyCNs { 159 appendFn(cn) 160 } 161 } 162 }