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 }