github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekalog/entry_pool_private.go (about)

     1  // Copyright © 2020-2021. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekalog
     7  
     8  import (
     9  	"runtime"
    10  	"sync"
    11  	"sync/atomic"
    12  
    13  	"github.com/qioalice/ekago/v3/internal/ekaletter"
    14  )
    15  
    16  type (
    17  	// EntryPoolStat is an internal struct that allows you to inspect
    18  	// how Logger's Entry pool utilized and it's current state.
    19  	EntryPoolStat struct {
    20  
    21  		// AllocCalls is how much absolutely new Entry objects
    22  		// with included ekaletter.LetterField are created using new RAM slice.
    23  		AllocCalls uint64
    24  
    25  		// NewCalls is how much attempts both of to allocate a new Entry objects
    26  		// or pop an one from Entry's pool were here.
    27  		//
    28  		// Once again.
    29  		// It contains AllocCalls + popping an oldest (and prepared to reuse)
    30  		// Entry objects from its pool.
    31  		NewCalls uint64
    32  
    33  		// ReleaseCalls is how much Entry objects were returned to its pool
    34  		// and prepared for being reused.
    35  		ReleaseCalls uint64
    36  	}
    37  )
    38  
    39  // EPS returns an EntryPoolStat object that contains an info about utilizing
    40  // Logger's Entry pool. Using that info you can figure out how often
    41  // a new Logger's Entry objects are created and how often the oldest ones
    42  // are reused.
    43  //
    44  // In 99% cases you don't need to know that stat,
    45  // and you should not to worry about that.
    46  func EPS() EntryPoolStat {
    47  	return EntryPoolStat{
    48  		AllocCalls:   atomic.LoadUint64(&eps.AllocCalls),
    49  		NewCalls:     atomic.LoadUint64(&eps.NewCalls),
    50  		ReleaseCalls: atomic.LoadUint64(&eps.ReleaseCalls),
    51  	}
    52  }
    53  
    54  var (
    55  	// entryPool is the pool of Entry (with allocated ekaletter.Letter) objects
    56  	// for being reused.
    57  	entryPool sync.Pool
    58  
    59  	// eps contains current state of Entry's pool utilizing,
    60  	// and its copy is returned by EPS() function.
    61  	eps EntryPoolStat
    62  )
    63  
    64  // allocEntry creates a new Entry object, creates a new ekaletter.Letter object inside,
    65  // performs base initialization and returns it.
    66  func allocEntry() any {
    67  
    68  	e := new(Entry)
    69  	e.LogLetter = new(ekaletter.Letter)
    70  	e.LogLetter.Messages = make([]ekaletter.LetterMessage, 0, 1)
    71  
    72  	runtime.SetFinalizer(e, releaseEntryForFinalizer)
    73  	e.needSetFinalizer = false
    74  
    75  	// SystemFields is used for saving Entry's meta data.
    76  	// https://github.com/qioalice/ekago/internal/letter/letter.go
    77  
    78  	// TODO: Is there any meta info we have to save to the SystemFields?
    79  	// TODO: Is there something we need to save to e.LogLetter.something?
    80  
    81  	atomic.AddUint64(&eps.AllocCalls, 1)
    82  	return e
    83  }
    84  
    85  // acquireEntry returns a new *Entry object from the Entry's pool or newly instantiated.
    86  func acquireEntry() *Entry {
    87  	atomic.AddUint64(&eps.NewCalls, 1)
    88  	return entryPool.Get().(*Entry).prepare()
    89  }
    90  
    91  // releaseEntry returns Entry to the Entry's pool for being reused in the future
    92  // and that Entry could be obtained later using acquireEntry().
    93  func releaseEntry(e *Entry) {
    94  	atomic.AddUint64(&eps.ReleaseCalls, 1)
    95  	entryPool.Put(e.cleanup())
    96  }
    97  
    98  // releaseEntryForFinalizer is a callback for runtime.SetFinalizer()
    99  // that allows to return an Entry to its pool if it's gone out of scope
   100  // without automatic returning to its pool by any Logger's finisher.
   101  func releaseEntryForFinalizer(e *Entry) {
   102  	e.needSetFinalizer = true
   103  	releaseEntry(e)
   104  }