github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekaerr/error_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 ekaerr 7 8 import ( 9 "runtime" 10 "sync" 11 "sync/atomic" 12 13 "github.com/qioalice/ekago/v3/internal/ekaletter" 14 ) 15 16 type ( 17 // ErrorPoolStat is an internal struct that allows you to inspect 18 // how Error's pool utilized and it's current state. 19 ErrorPoolStat struct { 20 21 // AllocCalls is how much absolutely new Error 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 Error objects 26 // or pop an one from Error's pool were here. 27 // 28 // Once again. 29 // It contains AllocCalls + popping an oldest (and prepared to reuse) 30 // Error objects from its pool. 31 NewCalls uint64 32 33 // ReleaseCalls is how much Error 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() (eps ErrorPoolStat) { 47 eps.AllocCalls = atomic.LoadUint64(&eps.AllocCalls) 48 eps.NewCalls = atomic.LoadUint64(&eps.NewCalls) 49 eps.ReleaseCalls = atomic.LoadUint64(&eps.ReleaseCalls) 50 return 51 } 52 53 var ( 54 // errorPool is the pool of Error (with allocated ekaletter.Letter) objects 55 // for being reused. 56 errorPool sync.Pool 57 58 // eps contains current state of Error's pool utilizing, 59 // and its copy is returned by EPS() function. 60 eps ErrorPoolStat 61 ) 62 63 // allocError creates a new Error object, creates a new ekaletter.Letter object inside, 64 // performs base initialization and returns it. 65 func allocError() any { 66 67 e := new(Error) 68 e.letter = new(ekaletter.Letter) 69 e.letter.Messages = make([]ekaletter.LetterMessage, 0, 8) 70 e.letter.Fields = make([]ekaletter.LetterField, 0, 16) 71 72 runtime.SetFinalizer(e, releaseErrorForFinalizer) 73 e.needSetFinalizer = false 74 75 // SystemFields is used for saving Error's meta data. 76 77 e.letter.SystemFields = make([]ekaletter.LetterField, 3) 78 79 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_CLASS_ID].Key = "error_class_id" 80 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_CLASS_ID].Kind |= 81 ekaletter.KIND_FLAG_SYSTEM | ekaletter.KIND_SYS_TYPE_EKAERR_CLASS_ID 82 83 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_CLASS_NAME].Key = "error_class_name" 84 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_CLASS_NAME].Kind |= 85 ekaletter.KIND_FLAG_SYSTEM | ekaletter.KIND_SYS_TYPE_EKAERR_CLASS_NAME 86 87 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_ERROR_ID].Key = "error_id" 88 e.letter.SystemFields[_ERR_SYS_FIELD_IDX_ERROR_ID].Kind |= 89 ekaletter.KIND_FLAG_SYSTEM | ekaletter.KIND_SYS_TYPE_EKAERR_UUID 90 91 atomic.AddUint64(&eps.AllocCalls, 1) 92 return e 93 } 94 95 // acquireError returns a new *Error object from the Error's pool or newly instantiated. 96 func acquireError() *Error { 97 atomic.AddUint64(&eps.NewCalls, 1) 98 return errorPool.Get().(*Error).prepare() 99 } 100 101 // releaseError returns Error to the Error's pool for being reused in the future 102 // and that Error could be obtained later using acquireError(). 103 func releaseError(e *Error) { 104 atomic.AddUint64(&eps.ReleaseCalls, 1) 105 errorPool.Put(e.cleanup()) 106 } 107 108 // releaseErrorForFinalizer is a callback for runtime.SetFinalizer() 109 // that allows to return an Error to its pool if it's gone out of scope 110 // without automatic returning to its pool by any ekalog.Logger's finisher. 111 func releaseErrorForFinalizer(e *Error) { 112 e.needSetFinalizer = true 113 releaseError(e) 114 }