github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/containers/pool.go (about)

     1  // Copyright 2021 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 containers
    16  
    17  import (
    18  	"fmt"
    19  	"sync/atomic"
    20  	_ "unsafe"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    23  	"github.com/matrixorigin/matrixone/pkg/container/types"
    24  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    25  	"github.com/matrixorigin/matrixone/pkg/util/metric/stats"
    26  )
    27  
    28  const (
    29  	// fix sized / (varlen + fix sized)
    30  	defaultFixedSizeRatio = 0.6
    31  
    32  	// default max alloaction size for a vector
    33  	defaultAllocLimit = 1024 * 1024 * 2 // 2MB
    34  )
    35  
    36  var _vectorPoolAlloactor *mpool.MPool
    37  
    38  func init() {
    39  	var err error
    40  	if _vectorPoolAlloactor, err = mpool.NewMPool(
    41  		"taeVectorPool", 0, mpool.NoFixed,
    42  	); err != nil {
    43  		panic(err)
    44  	}
    45  }
    46  
    47  func GetDefaultVectorPoolALLocator() *mpool.MPool {
    48  	return _vectorPoolAlloactor
    49  }
    50  
    51  type VectorPoolOption func(*VectorPool)
    52  
    53  func WithAllocationLimit(maxv int) VectorPoolOption {
    54  	return func(p *VectorPool) {
    55  		p.maxAlloc = maxv
    56  	}
    57  }
    58  
    59  func WithFixedSizeRatio(ratio float64) VectorPoolOption {
    60  	return func(p *VectorPool) {
    61  		p.ratio = ratio
    62  	}
    63  }
    64  
    65  func WithMPool(mp *mpool.MPool) VectorPoolOption {
    66  	return func(p *VectorPool) {
    67  		p.mp = mp
    68  	}
    69  }
    70  
    71  type vectorPoolElement struct {
    72  	pool  *VectorPool
    73  	mp    *mpool.MPool
    74  	vec   *vector.Vector
    75  	inUse atomic.Bool
    76  }
    77  
    78  func (e *vectorPoolElement) tryReuse(t *types.Type) bool {
    79  	if e.inUse.CompareAndSwap(false, true) {
    80  		e.vec.ResetWithNewType(t)
    81  		return true
    82  	}
    83  	return false
    84  }
    85  
    86  func (e *vectorPoolElement) put() {
    87  	if e.vec.Allocated() > e.pool.maxAlloc {
    88  		newVec := vector.NewVec(*e.vec.GetType())
    89  		e.vec.Free(e.mp)
    90  		e.vec = newVec
    91  		e.pool.resetStats.Add(1)
    92  	}
    93  	if !e.inUse.CompareAndSwap(true, false) {
    94  		panic("vectorPoolElement.put: vector is not in use")
    95  	}
    96  }
    97  
    98  func (e *vectorPoolElement) isIdle() bool {
    99  	return !e.inUse.Load()
   100  }
   101  
   102  type VectorPool struct {
   103  	name           string
   104  	maxAlloc       int
   105  	ratio          float64
   106  	fixSizedPool   []*vectorPoolElement
   107  	varlenPool     []*vectorPoolElement
   108  	fixHitStats    stats.Counter
   109  	varlenHitStats stats.Counter
   110  	resetStats     stats.Counter
   111  	totalStats     stats.Counter
   112  	mp             *mpool.MPool
   113  }
   114  
   115  func NewVectorPool(name string, cnt int, opts ...VectorPoolOption) *VectorPool {
   116  	p := &VectorPool{
   117  		name:  name,
   118  		ratio: -1,
   119  	}
   120  	for _, opt := range opts {
   121  		opt(p)
   122  	}
   123  	if p.mp == nil {
   124  		p.mp = _vectorPoolAlloactor
   125  	}
   126  	if p.maxAlloc <= 0 {
   127  		p.maxAlloc = defaultAllocLimit
   128  	}
   129  	if p.ratio < 0 {
   130  		p.ratio = defaultFixedSizeRatio
   131  	}
   132  
   133  	cnt1 := int(float64(cnt) * p.ratio)
   134  	cnt2 := cnt - cnt1
   135  	p.fixSizedPool = make([]*vectorPoolElement, 0, cnt1)
   136  	p.varlenPool = make([]*vectorPoolElement, 0, cnt2)
   137  
   138  	for i := 0; i < cnt1; i++ {
   139  		t := types.T_int64.ToType()
   140  		p.fixSizedPool = append(p.fixSizedPool, newVectorElement(p, &t, p.mp))
   141  	}
   142  	for i := 0; i < cnt2; i++ {
   143  		t := types.T_varchar.ToType()
   144  		p.varlenPool = append(p.varlenPool, newVectorElement(p, &t, p.mp))
   145  	}
   146  	return p
   147  }
   148  
   149  func (p *VectorPool) String() string {
   150  	fixedUsedCnt, _ := p.FixedSizeUsed(false)
   151  	varlenUsedCnt, _ := p.VarlenUsed(false)
   152  	usedCnt := fixedUsedCnt + varlenUsedCnt
   153  	fixHit := p.fixHitStats.Load()
   154  	varlenHit := p.varlenHitStats.Load()
   155  	hit := fixHit + varlenHit
   156  	str := fmt.Sprintf(
   157  		"VectorPool[%s][%d/%d]: FixSizedVec[%d/%d] VarlenVec[%d/%d], Reset/Hit/totalStats:[%d/(%d,%d)%d/%d]",
   158  		p.name,                                /* name */
   159  		usedCnt,                               /* totalStats used vector cnt */
   160  		len(p.fixSizedPool)+len(p.varlenPool), /* totalStats vector cnt */
   161  		fixedUsedCnt,                          /* used fixed sized vector cnt */
   162  		len(p.fixSizedPool),                   /* totalStats fixed sized vector cnt */
   163  		varlenUsedCnt,                         /* used varlen vector cnt */
   164  		len(p.varlenPool),                     /* totalStats varlen vector cnt */
   165  		p.resetStats.Load(),                   /* reset cnt */
   166  		fixHit,                                /* fixed sized vector hit cnt */
   167  		varlenHit,                             /* varlen vector hit cnt */
   168  		hit,                                   /* hit cnt */
   169  		p.totalStats.Load(),                   /* totalStats cnt */
   170  	)
   171  	return str
   172  }
   173  
   174  func (p *VectorPool) GetVector(t *types.Type) *vectorWrapper {
   175  	p.totalStats.Add(1)
   176  	if t.IsFixedLen() {
   177  		if len(p.fixSizedPool) > 0 {
   178  			for i := 0; i < 4; i++ {
   179  				idx := fastrand() % uint32(len(p.fixSizedPool))
   180  				element := p.fixSizedPool[idx]
   181  				if element.tryReuse(t) {
   182  					p.fixHitStats.Add(1)
   183  					return &vectorWrapper{
   184  						wrapped: element.vec,
   185  						mpool:   element.mp,
   186  						element: element,
   187  					}
   188  				}
   189  			}
   190  		}
   191  	} else {
   192  		if len(p.varlenPool) > 0 {
   193  			for i := 0; i < 4; i++ {
   194  				idx := fastrand() % uint32(len(p.varlenPool))
   195  				element := p.varlenPool[idx]
   196  				if element.tryReuse(t) {
   197  					p.varlenHitStats.Add(1)
   198  					return &vectorWrapper{
   199  						wrapped: element.vec,
   200  						mpool:   element.mp,
   201  						element: element,
   202  					}
   203  				}
   204  			}
   205  		}
   206  	}
   207  
   208  	return NewVector(*t, Options{Allocator: p.mp})
   209  }
   210  
   211  func (p *VectorPool) GetMPool() *mpool.MPool {
   212  	return p.mp
   213  }
   214  
   215  func (p *VectorPool) Allocated() int {
   216  	size := 0
   217  	size += p.FixedSizeAllocated()
   218  	size += p.VarlenaSizeAllocated()
   219  	return size
   220  }
   221  
   222  func (p *VectorPool) FixedSizeAllocated() int {
   223  	size := 0
   224  	for _, element := range p.fixSizedPool {
   225  		size += element.vec.Allocated()
   226  	}
   227  	return size
   228  }
   229  
   230  func (p *VectorPool) VarlenaSizeAllocated() int {
   231  	size := 0
   232  	for _, element := range p.varlenPool {
   233  		size += element.vec.Allocated()
   234  	}
   235  	return size
   236  }
   237  
   238  func (p *VectorPool) FixedSizeUsed(isUnsafe bool) (int, int) {
   239  	size := 0
   240  	cnt := 0
   241  	for _, element := range p.fixSizedPool {
   242  		if element.isIdle() {
   243  			continue
   244  		}
   245  		if isUnsafe {
   246  			size += element.vec.Allocated()
   247  		}
   248  		cnt++
   249  	}
   250  	return cnt, size
   251  }
   252  
   253  func (p *VectorPool) VarlenUsed(isUnsafe bool) (int, int) {
   254  	size := 0
   255  	cnt := 0
   256  	for _, element := range p.varlenPool {
   257  		if element.isIdle() {
   258  			continue
   259  		}
   260  		if isUnsafe {
   261  			size += element.vec.Allocated()
   262  		}
   263  		cnt++
   264  	}
   265  	return cnt, size
   266  }
   267  
   268  func (p *VectorPool) Used(isUnsafe bool) (int, int) {
   269  	cnt, size := p.FixedSizeUsed(isUnsafe)
   270  	cnt2, size2 := p.VarlenUsed(isUnsafe)
   271  	cnt += cnt2
   272  	size += size2
   273  	return cnt, size
   274  }
   275  
   276  // Only for test
   277  // It is not safe to call Destory
   278  func (p *VectorPool) Destory() {
   279  	fixSizedPool := p.fixSizedPool
   280  	varlenPool := p.varlenPool
   281  	mp := p.mp
   282  	p.mp = nil
   283  	p.fixSizedPool = nil
   284  	p.varlenPool = nil
   285  
   286  	for _, elem := range fixSizedPool {
   287  		elem.vec.Free(mp)
   288  	}
   289  	for _, elem := range varlenPool {
   290  		elem.vec.Free(mp)
   291  	}
   292  }
   293  
   294  func newVectorElement(pool *VectorPool, t *types.Type, mp *mpool.MPool) *vectorPoolElement {
   295  	vec := vector.NewVec(*t)
   296  	element := &vectorPoolElement{
   297  		pool: pool,
   298  		mp:   mp,
   299  		vec:  vec,
   300  	}
   301  	return element
   302  }
   303  
   304  //go:linkname fastrand runtime.fastrand
   305  func fastrand() uint32