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 }