github.com/matrixorigin/matrixone@v1.2.0/pkg/common/reuse/factory.go (about)

     1  // Copyright 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 reuse
    16  
    17  import (
    18  	"fmt"
    19  	"sync/atomic"
    20  	"unsafe"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    23  )
    24  
    25  var (
    26  	pools = map[unsafe.Pointer]any{}
    27  )
    28  
    29  var (
    30  	SyncBased  = SPI(0)
    31  	MpoolBased = SPI(1)
    32  
    33  	defaultSPI    = SyncBased
    34  	enableChecker atomic.Bool
    35  	enableVerbose atomic.Bool
    36  )
    37  
    38  // SPI choose pool implementation
    39  type SPI int
    40  
    41  func use(spi SPI) {
    42  	defaultSPI = spi
    43  }
    44  
    45  // DefaultOptions default options
    46  func DefaultOptions[T ReusableObject]() *Options[T] {
    47  	return &Options[T]{}
    48  }
    49  
    50  // WithReleaseFunc with specified release function. The release function is used to
    51  // release resources before gc.
    52  func (opts *Options[T]) WithReleaseFunc(release func(*T)) *Options[T] {
    53  	opts.release = release
    54  	return opts
    55  }
    56  
    57  // WithEnableChecker enable check double free, leak free.
    58  func (opts *Options[T]) WithEnableChecker() *Options[T] {
    59  	opts.enableChecker = true
    60  	return opts
    61  }
    62  
    63  func (opts *Options[T]) withGCRecover(fn func()) *Options[T] {
    64  	opts.gcRecover = fn
    65  	return opts
    66  }
    67  
    68  func (opts *Options[T]) adjust() {
    69  	if opts.release == nil {
    70  		opts.release = func(*T) {}
    71  	}
    72  	if opts.memCapacity == 0 {
    73  		opts.memCapacity = mpool.MB
    74  	}
    75  }
    76  
    77  // CreatePool create pool instance.
    78  func CreatePool[T ReusableObject](
    79  	new func() *T,
    80  	reset func(*T),
    81  	opts *Options[T]) {
    82  	if p := get[T](); p != nil {
    83  		var v *T
    84  		panic(fmt.Sprintf("%T pool already created", v))
    85  	}
    86  
    87  	tp := typeOf[T]()
    88  	switch defaultSPI {
    89  	case SyncBased:
    90  		pools[tp] = newSyncPoolBased(new, reset, opts)
    91  	case MpoolBased:
    92  		pools[tp] = newMpoolBased(mpool.MB*5, opts)
    93  	}
    94  }
    95  
    96  // Alloc allocates a pooled object.
    97  func Alloc[T ReusableObject](p Pool[T]) *T {
    98  	if p == nil {
    99  		var v T
   100  		p = get[T]()
   101  		if p == nil {
   102  			panic(fmt.Sprintf("%T pool not created", v))
   103  		}
   104  	}
   105  	return p.Alloc()
   106  }
   107  
   108  // Free free a pooled object.
   109  func Free[T ReusableObject](v *T, p Pool[T]) {
   110  	if p == nil {
   111  		p = get[T]()
   112  	}
   113  	if p == nil {
   114  		panic(fmt.Sprintf("%T pool not created", v))
   115  	}
   116  	p.Free(v)
   117  }
   118  
   119  func get[T ReusableObject]() Pool[T] {
   120  	if pool, ok := pools[typeOf[T]()]; ok {
   121  		return pool.(Pool[T])
   122  	}
   123  	return nil
   124  }
   125  
   126  func typeOf[T any]() unsafe.Pointer {
   127  	var v *T
   128  	i := any(v)
   129  	// any is a fat point and reflect.Type is a *abi.Type
   130  	// type emptyInterface struct {
   131  	// 	typ  *abi.Type
   132  	// 	word unsafe.Pointer
   133  	// }
   134  	return *(*unsafe.Pointer)(unsafe.Pointer(&i))
   135  }