github.com/XiaoMi/Gaea@v1.2.5/cc/service/service.go (about)

     1  // Copyright 2019 The Gaea Authors. All Rights Reserved.
     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 service
    16  
    17  import (
    18  	"fmt"
    19  	"sync"
    20  
    21  	"github.com/XiaoMi/Gaea/cc/proxy"
    22  	"github.com/XiaoMi/Gaea/log"
    23  	"github.com/XiaoMi/Gaea/models"
    24  )
    25  
    26  const (
    27  	PREPARE_RETRY_TIMES = 3
    28  	COMMIT_RETRY_TIMES  = 1
    29  )
    30  
    31  func getCoordinatorRoot(cluster string) string {
    32  	if cluster != "" {
    33  		return "/" + cluster
    34  	}
    35  	return cluster
    36  }
    37  
    38  // ListNamespace return names of all namespace
    39  func ListNamespace(cfg *models.CCConfig, cluster string) ([]string, error) {
    40  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
    41  	mConn := models.NewStore(client)
    42  	defer mConn.Close()
    43  	return mConn.ListNamespace()
    44  }
    45  
    46  // QueryNamespace return information of namespace specified by names
    47  func QueryNamespace(names []string, cfg *models.CCConfig, cluster string) (data []*models.Namespace, err error) {
    48  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
    49  	mConn := models.NewStore(client)
    50  	defer mConn.Close()
    51  	for _, v := range names {
    52  		namespace, err := mConn.LoadNamespace(cfg.EncryptKey, v)
    53  		if err != nil {
    54  			log.Warn("load namespace %s failed, %v", v, err.Error())
    55  			return nil, err
    56  		}
    57  		if namespace == nil {
    58  			log.Warn("namespace %s not found", v)
    59  			return data, nil
    60  		}
    61  		data = append(data, namespace)
    62  	}
    63  
    64  	return data, nil
    65  }
    66  
    67  // ModifyNamespace create or modify namespace
    68  func ModifyNamespace(namespace *models.Namespace, cfg *models.CCConfig, cluster string) (err error) {
    69  	if err = namespace.Verify(); err != nil {
    70  		return fmt.Errorf("verify namespace error: %v", err)
    71  	}
    72  
    73  	// create/modify will save encrypted data default
    74  	if err = namespace.Encrypt(cfg.EncryptKey); err != nil {
    75  		return fmt.Errorf("encrypt namespace error: %v", err)
    76  	}
    77  
    78  	// sink namespace
    79  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
    80  	storeConn := models.NewStore(client)
    81  	defer storeConn.Close()
    82  
    83  	if err := storeConn.UpdateNamespace(namespace); err != nil {
    84  		log.Warn("update namespace failed, %s", string(namespace.Encode()))
    85  		return err
    86  	}
    87  
    88  	// proxies ready to reload config
    89  	proxies, err := storeConn.ListProxyMonitorMetrics()
    90  	if err != nil {
    91  		log.Warn("list proxies failed, %v", err)
    92  		return err
    93  	}
    94  
    95  	wg := sync.WaitGroup{}
    96  	// prepare phase
    97  	for _, v := range proxies {
    98  		wg.Add(1)
    99  		go func(v *models.ProxyMonitorMetric) {
   100  			for i := 0; i < PREPARE_RETRY_TIMES; i++ {
   101  				if err = proxy.PrepareConfig(v.IP+":"+v.AdminPort, namespace.Name, cfg); err == nil {
   102  					break
   103  				}
   104  				log.Warn("namespace %s, proxy prepare retry %d", namespace.Name, i)
   105  			}
   106  			if err != nil {
   107  				return
   108  			}
   109  			wg.Done()
   110  		}(v)
   111  	}
   112  	wg.Wait()
   113  
   114  	// commit phase
   115  	for _, v := range proxies {
   116  		wg.Add(1)
   117  		go func(v *models.ProxyMonitorMetric) {
   118  			for i := 0; i < COMMIT_RETRY_TIMES; i++ {
   119  				if err := proxy.CommitConfig(v.IP+":"+v.AdminPort, namespace.Name, cfg); err == nil {
   120  					break
   121  				}
   122  				log.Warn("namespace %s, proxy prepare retry %d", namespace.Name, i)
   123  			}
   124  			if err != nil {
   125  				return
   126  			}
   127  			wg.Done()
   128  		}(v)
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  // DelNamespace delete namespace
   135  func DelNamespace(name string, cfg *models.CCConfig, cluster string) error {
   136  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
   137  	mConn := models.NewStore(client)
   138  	defer mConn.Close()
   139  
   140  	if err := mConn.DelNamespace(name); err != nil {
   141  		log.Warn("delete namespace %s failed, %s", name, err.Error())
   142  		return err
   143  	}
   144  
   145  	proxies, err := mConn.ListProxyMonitorMetrics()
   146  	if err != nil {
   147  		log.Warn("list proxy failed, %s", err.Error())
   148  		return err
   149  	}
   150  
   151  	for _, v := range proxies {
   152  		err := proxy.DelNamespace(v.IP+":"+v.AdminPort, name, cfg)
   153  		if err != nil {
   154  			log.Warn("delete namespace %s in proxy %s failed, err: %s", name, v.IP, err.Error())
   155  			return err
   156  		}
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  // SQLFingerprint return sql fingerprints of all proxy
   163  func SQLFingerprint(name string, cfg *models.CCConfig, cluster string) (slowSQLs, errSQLs map[string]string, err error) {
   164  	slowSQLs = make(map[string]string, 16)
   165  	errSQLs = make(map[string]string, 16)
   166  	// list proxy
   167  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
   168  	mConn := models.NewStore(client)
   169  	defer mConn.Close()
   170  	proxies, err := mConn.ListProxyMonitorMetrics()
   171  	if err != nil {
   172  		log.Warn("list proxy failed, %v", err)
   173  		return nil, nil, err
   174  	}
   175  	wg := new(sync.WaitGroup)
   176  	respC := make(chan *proxy.SQLFingerprint, len(proxies))
   177  	// query sql fingerprints concurrently
   178  	for _, p := range proxies {
   179  		wg.Add(1)
   180  		host := p.IP + ":" + p.AdminPort
   181  		go func(host, name string) {
   182  			defer wg.Done()
   183  			r, err := proxy.QueryNamespaceSQLFingerprint(host, name, cfg)
   184  			if err != nil {
   185  				log.Warn("query namespace sql fingerprint failed ,%v", err)
   186  			}
   187  			respC <- r
   188  		}(host, name)
   189  	}
   190  	wg.Wait()
   191  	close(respC)
   192  
   193  	for r := range respC {
   194  		if r == nil {
   195  			continue
   196  		}
   197  		for k, v := range r.SlowSQL {
   198  			slowSQLs[k] = v
   199  		}
   200  		for k, v := range r.ErrorSQL {
   201  			errSQLs[k] = v
   202  		}
   203  	}
   204  
   205  	return
   206  }
   207  
   208  // ProxyConfigFingerprint return fingerprints of all proxy
   209  func ProxyConfigFingerprint(cfg *models.CCConfig, cluster string) (r map[string]string, err error) {
   210  	// list proxy
   211  	client := models.NewClient(cfg.CoordinatorType, cfg.CoordinatorAddr, cfg.UserName, cfg.Password, getCoordinatorRoot(cluster))
   212  	mConn := models.NewStore(client)
   213  	defer mConn.Close()
   214  	proxies, err := mConn.ListProxyMonitorMetrics()
   215  	if err != nil {
   216  		log.Warn("list proxy failed, %v", err)
   217  		return nil, err
   218  	}
   219  	wg := new(sync.WaitGroup)
   220  	r = make(map[string]string, len(proxies))
   221  	respC := make(chan map[string]string, len(proxies))
   222  	for _, p := range proxies {
   223  		host := p.IP + ":" + p.AdminPort
   224  		wg.Add(1)
   225  		go func(host string) {
   226  			defer wg.Done()
   227  			md5, err := proxy.QueryProxyConfigFingerprint(host, cfg)
   228  			if err != nil {
   229  				log.Warn("query config fingerprint of proxy failed, %s %v", host, err)
   230  			}
   231  			m := make(map[string]string, 1)
   232  			m[host] = md5
   233  			respC <- m
   234  		}(host)
   235  	}
   236  	wg.Wait()
   237  	close(respC)
   238  	for resp := range respC {
   239  		if resp == nil {
   240  			continue
   241  		}
   242  		for k, v := range resp {
   243  			r[k] = v
   244  		}
   245  	}
   246  	return
   247  }