github.com/matrixorigin/matrixone@v1.2.0/pkg/proxy/util.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 proxy
    16  
    17  import (
    18  	"crypto/md5"
    19  	"encoding/hex"
    20  	"encoding/json"
    21  	"net"
    22  	"sort"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/frontend"
    25  )
    26  
    27  // makeOKPacket returns an OK packet
    28  func makeOKPacket(l int) []byte {
    29  	data := make([]byte, l+4)
    30  	data[4] = 0
    31  	data[0] = byte(l)
    32  	data[1] = byte(l >> 8)
    33  	data[2] = byte(l >> 16)
    34  	data[3] = 1
    35  	return data
    36  }
    37  
    38  func isCmdQuery(p []byte) bool {
    39  	if len(p) > 4 && p[4] == byte(cmdQuery) {
    40  		return true
    41  	}
    42  	return false
    43  }
    44  
    45  func isCmdInitDB(p []byte) bool {
    46  	if len(p) > 4 && p[4] == byte(cmdInitDB) {
    47  		return true
    48  	}
    49  	return false
    50  }
    51  
    52  func isCmdStmtPrepare(p []byte) bool {
    53  	if len(p) > 4 && p[4] == byte(cmdStmtPrepare) {
    54  		return true
    55  	}
    56  	return false
    57  }
    58  
    59  func isCmdStmtClose(p []byte) bool {
    60  	if len(p) > 4 && p[4] == byte(cmdStmtClose) {
    61  		return true
    62  	}
    63  	return false
    64  }
    65  
    66  // isOKPacket returns true if []byte is a MySQL OK packet.
    67  func isOKPacket(p []byte) bool {
    68  	if len(p) > 4 && p[4] == 0 {
    69  		return true
    70  	}
    71  	return false
    72  }
    73  
    74  // isOKPacket returns true if []byte is a MySQL EOF packet.
    75  func isEOFPacket(p []byte) bool {
    76  	if len(p) > 4 && p[4] == 0xFE {
    77  		return true
    78  	}
    79  	return false
    80  }
    81  
    82  // isErrPacket returns true if []byte is a MySQL Err packet.
    83  func isErrPacket(p []byte) bool {
    84  	if len(p) > 4 && p[4] == 0xFF {
    85  		return true
    86  	}
    87  	return false
    88  }
    89  
    90  // packetToBytes convert Packet to bytes.
    91  func packetToBytes(p *frontend.Packet) []byte {
    92  	if p == nil || len(p.Payload) == 0 {
    93  		return nil
    94  	}
    95  	res := make([]byte, 4, 4+len(p.Payload))
    96  	length := len(p.Payload)
    97  	res[0] = byte(length)
    98  	res[1] = byte(length >> 8)
    99  	res[2] = byte(length >> 16)
   100  	res[3] = byte(p.SequenceID)
   101  	return append(res, p.Payload...)
   102  }
   103  
   104  // bytesToPacket convert bytes to Packet.
   105  func bytesToPacket(bs []byte) *frontend.Packet {
   106  	if len(bs) < 4 {
   107  		return nil
   108  	}
   109  	p := &frontend.Packet{
   110  		Length:     int32(bs[0]) | int32(bs[1])<<8 | int32(bs[2])<<16,
   111  		SequenceID: int8(bs[3]),
   112  		Payload:    bs[4:],
   113  	}
   114  	return p
   115  }
   116  
   117  // getStatement gets a statement from message bytes which is MySQL protocol.
   118  func getStatement(msg []byte) string {
   119  	return string(msg[5:])
   120  }
   121  
   122  // pickTunnels pick N tunnels from the given tunnels. Simply, just
   123  // pick the first N tunnels.
   124  func pickTunnels(tuns tunnelSet, n int) []*tunnel {
   125  	if len(tuns) == 0 || n <= 0 {
   126  		return nil
   127  	}
   128  	size := n
   129  	if len(tuns) < n {
   130  		size = len(tuns)
   131  	}
   132  	ret := make([]*tunnel, 0, size)
   133  	i := 1
   134  	for t := range tuns {
   135  		// if the tunnel is in transfer intent state, we need to put it
   136  		// into the queue to speed up its transfer, and it does not count
   137  		// in the 'size'.
   138  		if t.transferIntent.Load() {
   139  			ret = append(ret, t)
   140  			continue
   141  		}
   142  		ret = append(ret, t)
   143  		i++
   144  		if i > size {
   145  			break
   146  		}
   147  	}
   148  	return ret
   149  }
   150  
   151  // sortMap sorts a complex map instance.
   152  func sortMap(target map[string]any) map[string]any {
   153  	sorted := sortSimpleMap(target)
   154  	res := make(map[string]any)
   155  	for k, v := range sorted {
   156  		if tv, s := v.(map[string]any); s {
   157  			res[k] = sortMap(tv)
   158  		} else if tv, s := v.([]any); s {
   159  			res[k] = sortSlice(tv)
   160  		} else {
   161  			res[k] = v
   162  		}
   163  	}
   164  	return res
   165  }
   166  
   167  // sortSlice sorts a slice instance.
   168  func sortSlice(target []any) []any {
   169  	hashArr := make(map[string]any)
   170  	for _, i := range target {
   171  		var tmpV any
   172  		var ha string
   173  		if ttv, ts := i.(map[string]any); ts {
   174  			tmpV = sortMap(ttv)
   175  			ha = rawHash(tmpV)
   176  		} else if ttv, ts := i.([]any); ts {
   177  			tmpV = sortSlice(ttv)
   178  			ha = rawHash(tmpV)
   179  		} else {
   180  			tmpV = i
   181  			ha = tmpV.(string)
   182  		}
   183  		hashArr[ha] = tmpV
   184  	}
   185  
   186  	sor := sortSimpleMap(hashArr)
   187  	sortKeys := getSortKeys(sor)
   188  	r := make([]any, 0, len(sortKeys))
   189  	for _, v := range sortKeys {
   190  		r = append(r, sor[v])
   191  	}
   192  	return r
   193  }
   194  
   195  // sortSimpleMap sort simple map by keys.
   196  func sortSimpleMap(target map[string]any) map[string]any {
   197  	keys := getSortKeys(target)
   198  	res := make(map[string]any, len(keys))
   199  	for _, k := range keys {
   200  		res[k] = target[k]
   201  	}
   202  	return res
   203  }
   204  
   205  // getSortKeys returns sorted keys in the map.
   206  func getSortKeys(target map[string]any) []string {
   207  	keys := make([]string, 0, len(target))
   208  	for k := range target {
   209  		keys = append(keys, k)
   210  	}
   211  	sort.Strings(keys)
   212  	return keys
   213  }
   214  
   215  // rawHash returns a string value as the hash result.
   216  func rawHash(t any) string {
   217  	sortBytes, err := json.Marshal(t)
   218  	if err != nil {
   219  		return ""
   220  	}
   221  	hash := md5.Sum(sortBytes)
   222  	return hex.EncodeToString(hash[:])
   223  }
   224  
   225  // containIP returns if the list of net.IPNet contains the IP address.
   226  func containIP(ipNetList []*net.IPNet, ip net.IP) bool {
   227  	for _, ipNet := range ipNetList {
   228  		if ipNet.Contains(ip) {
   229  			return true
   230  		}
   231  	}
   232  	return false
   233  }