CheckTrackingBufferPool undoes the effects of SetTrackingBufferPool, and fails unit tests if not all buffers were returned. It is invalid to invoke this function without previously having invoked SetTrackingBufferPool.
()
| 86 | // unit tests if not all buffers were returned. It is invalid to invoke this |
| 87 | // function without previously having invoked SetTrackingBufferPool. |
| 88 | func CheckTrackingBufferPool() { |
| 89 | p := (*globalPool.Load()).(*trackingBufferPool) |
| 90 | p.lock.Lock() |
| 91 | defer p.lock.Unlock() |
| 92 | |
| 93 | globalPool.Store(&p.pool) |
| 94 | |
| 95 | type uniqueTrace struct { |
| 96 | stack []uintptr |
| 97 | count int |
| 98 | } |
| 99 | |
| 100 | var totalLeakedBuffers int |
| 101 | var uniqueTraces []uniqueTrace |
| 102 | for _, stack := range p.allocatedBuffers { |
| 103 | idx, ok := slices.BinarySearchFunc(uniqueTraces, stack, func(trace uniqueTrace, stack []uintptr) int { |
| 104 | return slices.Compare(trace.stack, stack) |
| 105 | }) |
| 106 | if !ok { |
| 107 | uniqueTraces = slices.Insert(uniqueTraces, idx, uniqueTrace{stack: stack}) |
| 108 | } |
| 109 | uniqueTraces[idx].count++ |
| 110 | totalLeakedBuffers++ |
| 111 | } |
| 112 | |
| 113 | for _, ut := range uniqueTraces { |
| 114 | frames := runtime.CallersFrames(ut.stack) |
| 115 | var trace strings.Builder |
| 116 | for { |
| 117 | f, ok := frames.Next() |
| 118 | if !ok { |
| 119 | break |
| 120 | } |
| 121 | trace.WriteString(f.Function) |
| 122 | trace.WriteString("\n\t") |
| 123 | trace.WriteString(f.File) |
| 124 | trace.WriteString(":") |
| 125 | trace.WriteString(strconv.Itoa(f.Line)) |
| 126 | trace.WriteString("\n") |
| 127 | } |
| 128 | format := "%d allocated buffers never freed:\n%s" |
| 129 | args := []any{ut.count, trace.String()} |
| 130 | if failTestsOnLeakedBuffers { |
| 131 | p.logger.Errorf(format, args...) |
| 132 | } else { |
| 133 | p.logger.Logf("WARNING "+format, args...) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | if totalLeakedBuffers > 0 { |
| 138 | p.logger.Logf("%g%% of buffers never freed", float64(totalLeakedBuffers)/float64(p.bufferCount)) |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | type trackingBufferPool struct { |
| 143 | pool mem.BufferPool |