github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/builtin_vectorized.go (about)

     1  // Copyright 2020 WHTCORPS INC, 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 memex
    15  
    16  import (
    17  	"sync"
    18  
    19  	"github.com/whtcorpsinc/errors"
    20  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    21  	"github.com/whtcorpsinc/milevadb/types"
    22  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    23  )
    24  
    25  // defCausumnBufferSlabPredictor is used to allocate and release defCausumn buffer in vectorized evaluation.
    26  type defCausumnBufferSlabPredictor interface {
    27  	// get allocates a defCausumn buffer with the specific eval type and capacity.
    28  	// the allocator is not responsible for initializing the defCausumn, so please initialize it before using.
    29  	get(evalType types.EvalType, capacity int) (*chunk.DeferredCauset, error)
    30  	// put releases a defCausumn buffer.
    31  	put(buf *chunk.DeferredCauset)
    32  }
    33  
    34  // localSliceBuffer implements defCausumnBufferSlabPredictor interface.
    35  // It works like a concurrency-safe deque which is implemented by a dagger + slice.
    36  type localSliceBuffer struct {
    37  	sync.Mutex
    38  	buffers []*chunk.DeferredCauset
    39  	head    int
    40  	tail    int
    41  	size    int
    42  }
    43  
    44  func newLocalSliceBuffer(initCap int) *localSliceBuffer {
    45  	return &localSliceBuffer{buffers: make([]*chunk.DeferredCauset, initCap)}
    46  }
    47  
    48  var globalDeferredCausetSlabPredictor = newLocalSliceBuffer(1024)
    49  
    50  func newBuffer(evalType types.EvalType, capacity int) (*chunk.DeferredCauset, error) {
    51  	switch evalType {
    52  	case types.ETInt:
    53  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeLonglong), capacity), nil
    54  	case types.ETReal:
    55  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeDouble), capacity), nil
    56  	case types.ETDecimal:
    57  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeNewDecimal), capacity), nil
    58  	case types.ETDuration:
    59  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeDuration), capacity), nil
    60  	case types.ETDatetime, types.ETTimestamp:
    61  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeDatetime), capacity), nil
    62  	case types.ETString:
    63  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeString), capacity), nil
    64  	case types.ETJson:
    65  		return chunk.NewDeferredCauset(types.NewFieldType(allegrosql.TypeJSON), capacity), nil
    66  	}
    67  	return nil, errors.Errorf("get defCausumn buffer for unsupported EvalType=%v", evalType)
    68  }
    69  
    70  // GetDeferredCauset allocates a defCausumn buffer with the specific eval type and capacity.
    71  // the allocator is not responsible for initializing the defCausumn, so please initialize it before using.
    72  func GetDeferredCauset(evalType types.EvalType, capacity int) (*chunk.DeferredCauset, error) {
    73  	return globalDeferredCausetSlabPredictor.get(evalType, capacity)
    74  }
    75  
    76  // PutDeferredCauset releases a defCausumn buffer.
    77  func PutDeferredCauset(buf *chunk.DeferredCauset) {
    78  	globalDeferredCausetSlabPredictor.put(buf)
    79  }
    80  
    81  func (r *localSliceBuffer) get(evalType types.EvalType, capacity int) (*chunk.DeferredCauset, error) {
    82  	r.Lock()
    83  	if r.size > 0 {
    84  		buf := r.buffers[r.head]
    85  		r.head++
    86  		if r.head == len(r.buffers) {
    87  			r.head = 0
    88  		}
    89  		r.size--
    90  		r.Unlock()
    91  		return buf, nil
    92  	}
    93  	r.Unlock()
    94  	return newBuffer(evalType, capacity)
    95  }
    96  
    97  func (r *localSliceBuffer) put(buf *chunk.DeferredCauset) {
    98  	r.Lock()
    99  	if r.size == len(r.buffers) {
   100  		buffers := make([]*chunk.DeferredCauset, len(r.buffers)*2)
   101  		copy(buffers, r.buffers[r.head:])
   102  		copy(buffers[r.size-r.head:], r.buffers[:r.tail])
   103  		r.head = 0
   104  		r.tail = len(r.buffers)
   105  		r.buffers = buffers
   106  	}
   107  	r.buffers[r.tail] = buf
   108  	r.tail++
   109  	if r.tail == len(r.buffers) {
   110  		r.tail = 0
   111  	}
   112  	r.size++
   113  	r.Unlock()
   114  }
   115  
   116  // vecEvalIntByEvents uses the non-vectorized(event-based) interface `evalInt` to eval the memex.
   117  func vecEvalIntByEvents(sig builtinFunc, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   118  	n := input.NumEvents()
   119  	result.ResizeInt64(n, false)
   120  	i64s := result.Int64s()
   121  	for i := 0; i < n; i++ {
   122  		res, isNull, err := sig.evalInt(input.GetEvent(i))
   123  		if err != nil {
   124  			return err
   125  		}
   126  		result.SetNull(i, isNull)
   127  		i64s[i] = res
   128  	}
   129  	return nil
   130  }
   131  
   132  // vecEvalStringByEvents uses the non-vectorized(event-based) interface `evalString` to eval the memex.
   133  func vecEvalStringByEvents(sig builtinFunc, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   134  	n := input.NumEvents()
   135  	result.ReserveString(n)
   136  	for i := 0; i < n; i++ {
   137  		res, isNull, err := sig.evalString(input.GetEvent(i))
   138  		if err != nil {
   139  			return err
   140  		}
   141  		if isNull {
   142  			result.AppendNull()
   143  			continue
   144  		}
   145  		result.AppendString(res)
   146  	}
   147  	return nil
   148  }