Skip to content

Commit d7a4dab

Browse files
committed
bugfixes, cleanup, and add decay for max cache
1 parent e49e198 commit d7a4dab

File tree

4 files changed

+63
-27
lines changed

4 files changed

+63
-27
lines changed

config/config.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ const (
1919
type Configuration struct {
2020
LogLevel string
2121
Cache string
22-
Stats struct {
22+
Maximums struct {
23+
Interval time.Duration
24+
Decay int
25+
}
26+
Stats struct {
2327
General bool
2428
IP bool
2529
Interval time.Duration
@@ -99,6 +103,13 @@ func (conf *Configuration) validate() error {
99103
}
100104
}
101105

106+
if conf.Maximums.Interval < 0 {
107+
return errors.New("invalid configuration: Maximums.UpdateInterval must be >= 0")
108+
}
109+
if conf.Maximums.Decay < 0 {
110+
return errors.New("invalid configuration: Maximums.DecayHalfLifeUpdates must be >= 0")
111+
}
112+
102113
if conf.HTTP.Serve != "" {
103114
stat, err = os.Stat(conf.HTTP.Serve)
104115

config/embedded/trakx.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ loglevel: info
99
# backup files. Leave blank for default of XDG_CACHE_HOME/trakx
1010
cache:
1111

12+
# Record map size maxima for preallocation between runs.
13+
maximums:
14+
# How often to update stored maxima. Set to 0 to disable maximums tracking.
15+
update_interval: 5m
16+
# Decay half-life in update ticks (larger = slower decay). Set to 0 to disable decay.
17+
decay_half_life_updates: 2000
18+
1219
# Trakx can track statistic such as the number of announces, seeds, unique ips, etc.
1320
# They are published via go's expvar standard at '/stats'.
1421
stats:

daemon/run.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@ func RunWithOptions(conf *config.Configuration, opts RunOptions) {
5656
baseIntervalSeconds := uint(conf.Announce.Base / time.Second)
5757
fuzzIntervalSeconds := uint(conf.Announce.Fuzz / time.Second)
5858

59-
maxStore, err := maxcache.New(conf.Cache)
60-
if err != nil {
61-
zap.L().Warn("Failed to load maximums cache", zap.Error(err))
59+
var maxStore *maxcache.Store
60+
if conf.Maximums.Interval > 0 {
61+
maxStore, err = maxcache.New(conf.Cache, maxcache.Options{
62+
DecayHalfLifeUpdates: conf.Maximums.Decay,
63+
})
64+
if err != nil {
65+
zap.L().Warn("Failed to load maximums cache", zap.Error(err))
66+
}
6267
}
6368

6469
ipCollectorSize := 0
@@ -202,6 +207,8 @@ func RunWithOptions(conf *config.Configuration, opts RunOptions) {
202207
return
203208
}
204209

210+
zap.L().Info("Updating maximums cache")
211+
205212
if conf.Stats.General && conf.Stats.IP {
206213
ips := collector.IPs().Total()
207214
zap.L().Debug("Setting maximum", zap.Int("ips", ips))
@@ -212,13 +219,13 @@ func RunWithOptions(conf *config.Configuration, opts RunOptions) {
212219

213220
torrents := db.Torrents()
214221
zap.L().Debug("Setting maximum", zap.Int("torrents", torrents))
215-
if err := maxStore.Update(maxKeyDBTorrents, db.Torrents()); err != nil {
222+
if err := maxStore.Update(maxKeyDBTorrents, torrents); err != nil {
216223
zap.L().Warn("Failed to update maximums cache", zap.String("key", maxKeyDBTorrents), zap.Error(err))
217224
}
218225
}
219226

220227
if maxStore != nil {
221-
go utils.RunOn(maxcache.UpdateFrequency, updateMaximums)
228+
go utils.RunOn(conf.Maximums.Interval, updateMaximums)
222229
}
223230

224231
go signalHandler(trackers, func() error {

internal/maxcache/store.go

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,52 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"math"
78
"os"
89
"path/filepath"
9-
"strconv"
1010
"strings"
1111
"sync"
12-
"time"
1312
)
1413

1514
const (
16-
fileSuffix = ".maximum"
15+
fileSuffix = ".json"
1716
dirName = "maximums"
18-
19-
UpdateFrequency = time.Minute
2017
)
2118

2219
var ErrInvalidKey = errors.New("invalid maximums key")
2320

2421
type Store struct {
25-
dir string
26-
mu sync.Mutex
27-
values map[string]int
22+
dir string
23+
decayFactor float64
24+
mu sync.Mutex
25+
values map[string]int
2826
}
2927

3028
type record struct {
3129
Max int `json:"max"`
3230
}
3331

32+
type Options struct {
33+
DecayHalfLifeUpdates int
34+
}
35+
3436
// New creates a maximums store rooted at cacheDir/maximums.
3537
// It loads existing maxima if present.
36-
func New(cacheDir string) (*Store, error) {
38+
func New(cacheDir string, opts Options) (*Store, error) {
3739
dir := filepath.Join(cacheDir, dirName)
3840
if err := os.MkdirAll(dir, 0o700); err != nil {
3941
return nil, err
4042
}
4143

44+
decayFactor := 1.0
45+
if opts.DecayHalfLifeUpdates > 0 {
46+
decayFactor = math.Pow(0.5, 1.0/float64(opts.DecayHalfLifeUpdates))
47+
}
48+
4249
store := &Store{
43-
dir: dir,
44-
values: make(map[string]int),
50+
dir: dir,
51+
decayFactor: decayFactor,
52+
values: make(map[string]int),
4553
}
4654

4755
if err := store.load(); err != nil {
@@ -75,12 +83,20 @@ func (s *Store) Update(key string, value int) error {
7583
s.mu.Lock()
7684
defer s.mu.Unlock()
7785

78-
if value <= s.values[key] {
86+
current := s.values[key]
87+
next := current
88+
if s.decayFactor < 1 && current > 0 {
89+
next = int(math.Floor(float64(current) * s.decayFactor))
90+
}
91+
if value > next {
92+
next = value
93+
}
94+
if next == current {
7995
return nil
8096
}
8197

82-
s.values[key] = value
83-
return s.writeLocked(key, value)
98+
s.values[key] = next
99+
return s.writeLocked(key, next)
84100
}
85101

86102
func (s *Store) load() error {
@@ -172,15 +188,10 @@ func (s *Store) writeLocked(key string, value int) error {
172188

173189
func parseValue(data []byte) (int, error) {
174190
var rec record
175-
if err := json.Unmarshal(data, &rec); err == nil {
176-
return rec.Max, nil
177-
}
178-
179-
value, err := strconv.Atoi(strings.TrimSpace(string(data)))
180-
if err != nil {
191+
if err := json.Unmarshal(data, &rec); err != nil {
181192
return 0, err
182193
}
183-
return value, nil
194+
return rec.Max, nil
184195
}
185196

186197
func validateKey(key string) error {

0 commit comments

Comments
 (0)