github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/allegrosql.go (about)

     1  backup// Copyright 2020 WHTCORPS INC.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package allegrosql
    15  
    16  import (
    17  	"context"
    18  	"unsafe"
    19  
    20  	"github.com/whtcorpsinc/errors"
    21  	"github.com/whtcorpsinc/fidelpb/go-fidelpb"
    22  	"github.com/whtcorpsinc/milevadb/ekv"
    23  	"github.com/whtcorpsinc/milevadb/metrics"
    24  	"github.com/whtcorpsinc/milevadb/statistics"
    25  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    26  	"github.com/whtcorpsinc/milevadb/types"
    27  	"github.com/opentracing/opentracing-go"
    28  )
    29  
    30  
    31  func Select(ctx context.Context, sctx stochastikctx.Context, ekvReq *ekv.Request, fieldTypes []*types.FieldType, fb *statistics.QueryFeedback) (SelectResult, error) {
    32  	if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil {
    33  		span1 := span.Tracer().StartSpan("allegrosql.Select", opentracing.ChildOf(span.Context()))
    34  		defer span1.Finish()
    35  		ctx = opentracing.ContextWithSpan(ctx, span1)
    36  	}
    37  
    38  	// For testing purpose.
    39  	if hook := ctx.Value("CheckSelectRequestHook"); hook != nil {
    40  		hook.(func(*ekv.Request))(ekvReq)
    41  	}
    42  
    43  	if !sctx.GetStochastikVars().EnableStreaming {
    44  		ekvReq.Streaming = false
    45  	}
    46  	resp := sctx.GetClient().Send(ctx, ekvReq, sctx.GetStochastikVars().KVVars)
    47  	if resp == nil {
    48  		err := errors.New("client returns nil response")
    49  		return nil, err
    50  	}
    51  
    52  	label := metrics.LblGeneral
    53  	if sctx.GetStochastikVars().InRestrictedALLEGROSQL {
    54  		label = metrics.LblInternal
    55  	}
    56  
    57  	// ekvReq.MemTracker is used to trace and control memory usage in DistALLEGROSQL layer;
    58  	// for streamResult, since it is a pipeline which has no buffer, it's not necessary to trace it;
    59  	// for selectResult, we just use the ekvReq.MemTracker prepared for co-processor
    60  	// instead of creating a new one for simplification.
    61  	if ekvReq.Streaming {
    62  		return &streamResult{
    63  			label:      "posetPosetDag-stream",
    64  			sqlType:    label,
    65  			resp:       resp,
    66  			rowLen:     len(fieldTypes),
    67  			fieldTypes: fieldTypes,
    68  			ctx:        sctx,
    69  			feedback:   fb,
    70  		}, nil
    71  	}
    72  	encodetype := fidelpb.EncodeType_TypeDefault
    73  	if canUseChunkRPC(sctx) {
    74  		encodetype = fidelpb.EncodeType_TypeChunk
    75  	}
    76  	return &selectResult{
    77  		label:      "posetPosetDag",
    78  		resp:       resp,
    79  		rowLen:     len(fieldTypes),
    80  		fieldTypes: fieldTypes,
    81  		ctx:        sctx,
    82  		feedback:   fb,
    83  		sqlType:    label,
    84  		memTracker: ekvReq.MemTracker,
    85  		encodeType: encodetype,
    86  	}, nil
    87  }
    88  
    89  // SelectWithRuntimeStats sends a PosetDag request, returns SelectResult.
    90  // The difference from Select is that SelectWithRuntimeStats will set copCausetIDs into selectResult,
    91  // which can help selectResult to defCauslect runtime stats.
    92  func SelectWithRuntimeStats(ctx context.Context, sctx stochastikctx.Context, ekvReq *ekv.Request,
    93  	fieldTypes []*types.FieldType, fb *statistics.QueryFeedback, copCausetIDs []int, rootCausetID int) (SelectResult, error) {
    94  	sr, err := Select(ctx, sctx, ekvReq, fieldTypes, fb)
    95  	if err == nil {
    96  		if selectResult, ok := sr.(*selectResult); ok {
    97  			selectResult.copCausetIDs = copCausetIDs
    98  			selectResult.rootCausetID = rootCausetID
    99  		}
   100  	}
   101  	return sr, err
   102  }
   103  
   104  // Analyze do a analyze request.
   105  func Analyze(ctx context.Context, client ekv.Client, ekvReq *ekv.Request, vars *ekv.Variables,
   106  	isRestrict bool) (SelectResult, error) {
   107  	resp := client.Send(ctx, ekvReq, vars)
   108  	if resp == nil {
   109  		return nil, errors.New("client returns nil response")
   110  	}
   111  	label := metrics.LblGeneral
   112  	if isRestrict {
   113  		label = metrics.LblInternal
   114  	}
   115  	result := &selectResult{
   116  		label:      "analyze",
   117  		resp:       resp,
   118  		feedback:   statistics.NewQueryFeedback(0, nil, 0, false),
   119  		sqlType:    label,
   120  		encodeType: fidelpb.EncodeType_TypeDefault,
   121  	}
   122  	return result, nil
   123  }
   124  
   125  // Checksum sends a checksum request.
   126  func Checksum(ctx context.Context, client ekv.Client, ekvReq *ekv.Request, vars *ekv.Variables) (SelectResult, error) {
   127  	resp := client.Send(ctx, ekvReq, vars)
   128  	if resp == nil {
   129  		return nil, errors.New("client returns nil response")
   130  	}
   131  	result := &selectResult{
   132  		label:      "checksum",
   133  		resp:       resp,
   134  		feedback:   statistics.NewQueryFeedback(0, nil, 0, false),
   135  		sqlType:    metrics.LblGeneral,
   136  		encodeType: fidelpb.EncodeType_TypeDefault,
   137  	}
   138  	return result, nil
   139  }
   140  
   141  // SetEncodeType sets the encoding method for the PosetDagRequest. The supported encoding
   142  // methods are:
   143  // 1. TypeChunk: the result is encoded using the Chunk format, refer soliton/chunk/chunk.go
   144  // 2. TypeDefault: the result is encoded event by event
   145  func SetEncodeType(ctx stochastikctx.Context, posetPosetDagReq *fidelpb.PosetDagRequest) {
   146  	if canUseChunkRPC(ctx) {
   147  		posetPosetDagReq.EncodeType = fidelpb.EncodeType_TypeChunk
   148  		setChunkMemoryLayout(posetPosetDagReq)
   149  	} else {
   150  		posetPosetDagReq.EncodeType = fidelpb.EncodeType_TypeDefault
   151  	}
   152  }
   153  
   154  func canUseChunkRPC(ctx stochastikctx.Context) bool {
   155  	if !ctx.GetStochastikVars().EnableChunkRPC {
   156  		return false
   157  	}
   158  	if ctx.GetStochastikVars().EnableStreaming {
   159  		return false
   160  	}
   161  	if !checkAlignment() {
   162  		return false
   163  	}
   164  	return true
   165  }
   166  
   167  var supportedAlignment = unsafe.Sizeof(types.MyDecimal{}) == 40
   168  
   169  // checkAlignment checks the alignment in current system environment.
   170  // The alignment is influenced by system, machine and Golang version.
   171  // Using this function can guarantee the alignment is we want.
   172  func checkAlignment() bool {
   173  	return supportedAlignment
   174  }
   175  
   176  var systemEndian fidelpb.Endian
   177  
   178  // setChunkMemoryLayout sets the chunk memory layout for the PosetDagRequest.
   179  func setChunkMemoryLayout(posetPosetDagReq *fidelpb.PosetDagRequest) {
   180  	posetPosetDagReq.ChunkMemoryLayout = &fidelpb.ChunkMemoryLayout{Endian: GetSystemEndian()}
   181  }
   182  
   183  // GetSystemEndian gets the system endian.
   184  func GetSystemEndian() fidelpb.Endian {
   185  	return systemEndian
   186  }
   187  
   188  func init() {
   189  	i := 0x0100
   190  	ptr := unsafe.Pointer(&i)
   191  	if 0x01 == *(*byte)(ptr) {
   192  		systemEndian = fidelpb.Endian_BigEndian
   193  	} else {
   194  		systemEndian = fidelpb.Endian_LittleEndian
   195  	}
   196  }