github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/client/fetch_state_leakcheckpool_gen_test.go (about)

     1  // Copyright (c) 2021 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  // This file was automatically generated by genny.
    22  // Any changes will be lost if this file is regenerated.
    23  // see https://github.com/mauricelam/genny
    24  
    25  package client
    26  
    27  import (
    28  	"fmt"
    29  	"runtime/debug"
    30  	"sync"
    31  	"testing"
    32  
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  // Copyright (c) 2018 Uber Technologies, Inc.
    37  //
    38  // Permission is hereby granted, free of charge, to any person obtaining a copy
    39  // of this software and associated documentation files (the "Software"), to deal
    40  // in the Software without restriction, including without limitation the rights
    41  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    42  // copies of the Software, and to permit persons to whom the Software is
    43  // furnished to do so, subject to the following conditions:
    44  //
    45  // The above copyright notice and this permission notice shall be included in
    46  // all copies or substantial portions of the Software.
    47  //
    48  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    49  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    50  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    51  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    52  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    53  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    54  // THE SOFTWARE.
    55  
    56  // fetchStateEqualsFn allows users to override equality checks
    57  // for `fetchState` instances.
    58  type fetchStateEqualsFn func(a, b *fetchState) bool
    59  
    60  // fetchStateGetHookFn allows users to override properties on items
    61  // retrieved from the backing pools before returning in the Get()
    62  // path.
    63  type fetchStateGetHookFn func(*fetchState) *fetchState
    64  
    65  // leakcheckFetchStatePoolOpts allows users to override default behaviour.
    66  type leakcheckFetchStatePoolOpts struct {
    67  	DisallowUntrackedPuts bool
    68  	EqualsFn              fetchStateEqualsFn
    69  	GetHookFn             fetchStateGetHookFn
    70  }
    71  
    72  // newLeakcheckFetchStatePool returns a new leakcheckFetchStatePool.
    73  func newLeakcheckFetchStatePool(opts leakcheckFetchStatePoolOpts, backingPool fetchStatePool) *leakcheckFetchStatePool {
    74  	if opts.EqualsFn == nil {
    75  		// NB(prateek): fall-back to == in the worst case
    76  		opts.EqualsFn = func(a, b *fetchState) bool {
    77  			return a == b
    78  		}
    79  	}
    80  	return &leakcheckFetchStatePool{opts: opts, fetchStatePool: backingPool}
    81  }
    82  
    83  // leakcheckFetchStatePool wraps the underlying fetchStatePool to make it easier to
    84  // track leaks/allocs.
    85  type leakcheckFetchStatePool struct {
    86  	sync.Mutex
    87  	fetchStatePool
    88  	NumGets      int
    89  	NumPuts      int
    90  	PendingItems []leakcheckFetchState
    91  	AllGetItems  []leakcheckFetchState
    92  
    93  	opts leakcheckFetchStatePoolOpts
    94  }
    95  
    96  // leakcheckFetchState wraps `fetchState` instances along with their last Get() paths.
    97  type leakcheckFetchState struct {
    98  	Value         *fetchState
    99  	GetStacktrace []byte // GetStacktrace is the stacktrace for the Get() of this item
   100  }
   101  
   102  func (p *leakcheckFetchStatePool) Init() {
   103  	p.Lock()
   104  	defer p.Unlock()
   105  	p.fetchStatePool.Init()
   106  }
   107  
   108  func (p *leakcheckFetchStatePool) Get() *fetchState {
   109  	p.Lock()
   110  	defer p.Unlock()
   111  
   112  	e := p.fetchStatePool.Get()
   113  	if fn := p.opts.GetHookFn; fn != nil {
   114  		e = fn(e)
   115  	}
   116  
   117  	p.NumGets++
   118  	item := leakcheckFetchState{
   119  		Value:         e,
   120  		GetStacktrace: debug.Stack(),
   121  	}
   122  	p.PendingItems = append(p.PendingItems, item)
   123  	p.AllGetItems = append(p.AllGetItems, item)
   124  
   125  	return e
   126  }
   127  
   128  func (p *leakcheckFetchStatePool) Put(value *fetchState) {
   129  	p.Lock()
   130  	defer p.Unlock()
   131  
   132  	idx := -1
   133  	for i, item := range p.PendingItems {
   134  		if p.opts.EqualsFn(item.Value, value) {
   135  			idx = i
   136  			break
   137  		}
   138  	}
   139  
   140  	if idx == -1 && p.opts.DisallowUntrackedPuts {
   141  		panic(fmt.Errorf("untracked object (%v) returned to pool", value))
   142  	}
   143  
   144  	if idx != -1 {
   145  		// update slice
   146  		p.PendingItems = append(p.PendingItems[:idx], p.PendingItems[idx+1:]...)
   147  	}
   148  	p.NumPuts++
   149  
   150  	p.fetchStatePool.Put(value)
   151  }
   152  
   153  // Check ensures there are no leaks.
   154  func (p *leakcheckFetchStatePool) Check(t *testing.T) {
   155  	p.Lock()
   156  	defer p.Unlock()
   157  
   158  	require.Equal(t, p.NumGets, p.NumPuts)
   159  	require.Empty(t, p.PendingItems)
   160  }
   161  
   162  type leakcheckFetchStateFn func(e leakcheckFetchState)
   163  
   164  // CheckExtended ensures there are no leaks, and executes the specified fn
   165  func (p *leakcheckFetchStatePool) CheckExtended(t *testing.T, fn leakcheckFetchStateFn) {
   166  	p.Check(t)
   167  	p.Lock()
   168  	defer p.Unlock()
   169  	for _, e := range p.AllGetItems {
   170  		fn(e)
   171  	}
   172  }