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  }