accounting: fix memory leak from stats groups on long-running rcd
Before this change, `NewStats` stored the context it was created from on the `StatsInfo`. Stats groups are never freed -- they are only evicted once there are `--max-stats-groups` of them -- so each one kept its context, and everything reachable from it, alive for the life of the process. As the rc creates a group per call, that included the call's filters and their compiled regexps. The context was only ever used to get `ci.StatsFileNameLength` from the config. `StatsInfo` already stores that same `*fs.ConfigInfo`, read from the same context in `NewStats`. This change fixes the issue by passing the stored ci to `transferMap.String` and dropping the context from `StatsInfo`.
This commit is contained in:
@@ -33,7 +33,6 @@ var MaxCompletedTransfers = 100
|
||||
// to correctly count the updated fields
|
||||
type StatsInfo struct {
|
||||
mu sync.RWMutex
|
||||
ctx context.Context
|
||||
ci *fs.ConfigInfo
|
||||
bytes int64
|
||||
errors int64
|
||||
@@ -85,7 +84,6 @@ type averageValues struct {
|
||||
func NewStats(ctx context.Context) *StatsInfo {
|
||||
ci := fs.GetConfig(ctx)
|
||||
s := &StatsInfo{
|
||||
ctx: ctx,
|
||||
ci: ci,
|
||||
checking: newTransferMap(ci.Checkers, "checking"),
|
||||
transferring: newTransferMap(ci.Transfers, "transferring"),
|
||||
@@ -518,10 +516,10 @@ func (s *StatsInfo) String() string {
|
||||
// Add per transfer stats if required
|
||||
if !s.ci.StatsOneLine {
|
||||
if !s.checking.empty() {
|
||||
_, _ = fmt.Fprintf(buf, "Checking:\n%s\n", s.checking.String(s.ctx, s.inProgress, s.transferring))
|
||||
_, _ = fmt.Fprintf(buf, "Checking:\n%s\n", s.checking.String(s.ci, s.inProgress, s.transferring))
|
||||
}
|
||||
if !s.transferring.empty() {
|
||||
_, _ = fmt.Fprintf(buf, "Transferring:\n%s\n", s.transferring.String(s.ctx, s.inProgress, nil))
|
||||
_, _ = fmt.Fprintf(buf, "Transferring:\n%s\n", s.transferring.String(s.ci, s.inProgress, nil))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package accounting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"sort"
|
||||
@@ -91,10 +90,9 @@ func (tm *transferMap) _sortedSlice() []*Transfer {
|
||||
|
||||
// String returns string representation of map items excluding any in
|
||||
// exclude (if set).
|
||||
func (tm *transferMap) String(ctx context.Context, progress *inProgress, exclude *transferMap) string {
|
||||
func (tm *transferMap) String(ci *fs.ConfigInfo, progress *inProgress, exclude *transferMap) string {
|
||||
tm.mu.RLock()
|
||||
defer tm.mu.RUnlock()
|
||||
ci := fs.GetConfig(ctx)
|
||||
stringList := make([]string, 0, len(tm.items))
|
||||
for _, tr := range tm._sortedSlice() {
|
||||
var what = tr.what
|
||||
|
||||
Reference in New Issue
Block a user