Merge pull request #316 from mrd0ll4r/remove-time-now

Remove most calls to time.Now
This commit is contained in:
mrd0ll4r 2017-05-17 21:17:49 +02:00 committed by GitHub
commit 1cc0738cbe
4 changed files with 100 additions and 32 deletions

View file

@ -40,6 +40,10 @@ chihaya:
read_timeout: 5s read_timeout: 5s
write_timeout: 5s write_timeout: 5s
# Whether to time requests.
# Disabling this should increase performance/decrease load.
enable_request_timing: false
# This block defines configuration for the tracker's UDP interface. # This block defines configuration for the tracker's UDP interface.
# If you do not wish to run this, delete this section. # If you do not wish to run this, delete this section.
udp: udp:
@ -57,6 +61,10 @@ chihaya:
# The key used to encrypt connection IDs. # The key used to encrypt connection IDs.
private_key: "paste a random string here that will be used to hmac connection IDs" private_key: "paste a random string here that will be used to hmac connection IDs"
# Whether to time requests.
# Disabling this should increase performance/decrease load.
enable_request_timing: false
# This block defines configuration used for the storage of peer data. # This block defines configuration used for the storage of peer data.
storage: storage:
# The frequency which stale peers are removed. # The frequency which stale peers are removed.

View file

@ -62,25 +62,27 @@ func recordResponseDuration(action string, af *bittorrent.AddressFamily, err err
// Config represents all of the configurable options for an HTTP BitTorrent // Config represents all of the configurable options for an HTTP BitTorrent
// Frontend. // Frontend.
type Config struct { type Config struct {
Addr string `yaml:"addr"` Addr string `yaml:"addr"`
ReadTimeout time.Duration `yaml:"read_timeout"` ReadTimeout time.Duration `yaml:"read_timeout"`
WriteTimeout time.Duration `yaml:"write_timeout"` WriteTimeout time.Duration `yaml:"write_timeout"`
AllowIPSpoofing bool `yaml:"allow_ip_spoofing"` AllowIPSpoofing bool `yaml:"allow_ip_spoofing"`
RealIPHeader string `yaml:"real_ip_header"` RealIPHeader string `yaml:"real_ip_header"`
TLSCertPath string `yaml:"tls_cert_path"` TLSCertPath string `yaml:"tls_cert_path"`
TLSKeyPath string `yaml:"tls_key_path"` TLSKeyPath string `yaml:"tls_key_path"`
EnableRequestTiming bool `yaml:"enable_request_timing"`
} }
// LogFields renders the current config as a set of Logrus fields. // LogFields renders the current config as a set of Logrus fields.
func (cfg Config) LogFields() log.Fields { func (cfg Config) LogFields() log.Fields {
return log.Fields{ return log.Fields{
"addr": cfg.Addr, "addr": cfg.Addr,
"readTimeout": cfg.ReadTimeout, "readTimeout": cfg.ReadTimeout,
"writeTimeout": cfg.WriteTimeout, "writeTimeout": cfg.WriteTimeout,
"allowIPSpoofing": cfg.AllowIPSpoofing, "allowIPSpoofing": cfg.AllowIPSpoofing,
"realIPHeader": cfg.RealIPHeader, "realIPHeader": cfg.RealIPHeader,
"tlsCertPath": cfg.TLSCertPath, "tlsCertPath": cfg.TLSCertPath,
"tlsKeyPath": cfg.TLSKeyPath, "tlsKeyPath": cfg.TLSKeyPath,
"enableRequestTiming": cfg.EnableRequestTiming,
} }
} }
@ -168,9 +170,18 @@ func (f *Frontend) listenAndServe() error {
// announceRoute parses and responds to an Announce. // announceRoute parses and responds to an Announce.
func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
var err error var err error
start := time.Now() var start time.Time
if f.EnableRequestTiming {
start = time.Now()
}
var af *bittorrent.AddressFamily var af *bittorrent.AddressFamily
defer func() { recordResponseDuration("announce", af, err, time.Since(start)) }() defer func() {
if f.EnableRequestTiming {
recordResponseDuration("announce", af, err, time.Since(start))
} else {
recordResponseDuration("announce", af, err, time.Duration(0))
}
}()
req, err := ParseAnnounce(r, f.RealIPHeader, f.AllowIPSpoofing) req, err := ParseAnnounce(r, f.RealIPHeader, f.AllowIPSpoofing)
if err != nil { if err != nil {
@ -198,9 +209,18 @@ func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httpr
// scrapeRoute parses and responds to a Scrape. // scrapeRoute parses and responds to a Scrape.
func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
var err error var err error
start := time.Now() var start time.Time
if f.EnableRequestTiming {
start = time.Now()
}
var af *bittorrent.AddressFamily var af *bittorrent.AddressFamily
defer func() { recordResponseDuration("scrape", af, err, time.Since(start)) }() defer func() {
if f.EnableRequestTiming {
recordResponseDuration("scrape", af, err, time.Since(start))
} else {
recordResponseDuration("scrape", af, err, time.Duration(0))
}
}()
req, err := ParseScrape(r) req, err := ParseScrape(r)
if err != nil { if err != nil {

View file

@ -67,19 +67,21 @@ func recordResponseDuration(action string, af *bittorrent.AddressFamily, err err
// Config represents all of the configurable options for a UDP BitTorrent // Config represents all of the configurable options for a UDP BitTorrent
// Tracker. // Tracker.
type Config struct { type Config struct {
Addr string `yaml:"addr"` Addr string `yaml:"addr"`
PrivateKey string `yaml:"private_key"` PrivateKey string `yaml:"private_key"`
MaxClockSkew time.Duration `yaml:"max_clock_skew"` MaxClockSkew time.Duration `yaml:"max_clock_skew"`
AllowIPSpoofing bool `yaml:"allow_ip_spoofing"` AllowIPSpoofing bool `yaml:"allow_ip_spoofing"`
EnableRequestTiming bool `yaml:"enable_request_timing"`
} }
// LogFields renders the current config as a set of Logrus fields. // LogFields renders the current config as a set of Logrus fields.
func (cfg Config) LogFields() log.Fields { func (cfg Config) LogFields() log.Fields {
return log.Fields{ return log.Fields{
"addr": cfg.Addr, "addr": cfg.Addr,
"privateKey": cfg.PrivateKey, "privateKey": cfg.PrivateKey,
"maxClockSkew": cfg.MaxClockSkew, "maxClockSkew": cfg.MaxClockSkew,
"allowIPSpoofing": cfg.AllowIPSpoofing, "allowIPSpoofing": cfg.AllowIPSpoofing,
"enableRequestTiming": cfg.EnableRequestTiming,
} }
} }
@ -201,13 +203,20 @@ func (t *Frontend) listenAndServe() error {
} }
// Handle the request. // Handle the request.
start := time.Now() var start time.Time
if t.EnableRequestTiming {
start = time.Now()
}
action, af, err := t.handleRequest( action, af, err := t.handleRequest(
// Make sure the IP is copied, not referenced. // Make sure the IP is copied, not referenced.
Request{buffer[:n], append([]byte{}, addr.IP...)}, Request{buffer[:n], append([]byte{}, addr.IP...)},
ResponseWriter{t.socket, addr}, ResponseWriter{t.socket, addr},
) )
recordResponseDuration(action, af, err, time.Since(start)) if t.EnableRequestTiming {
recordResponseDuration(action, af, err, time.Since(start))
} else {
recordResponseDuration(action, af, err, time.Duration(0))
}
}() }()
} }
} }

View file

@ -6,6 +6,7 @@ import (
"net" "net"
"runtime" "runtime"
"sync" "sync"
"sync/atomic"
"time" "time"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
@ -99,6 +100,25 @@ func New(cfg Config) (storage.PeerStore, error) {
} }
}() }()
ps.wg.Add(1)
go func() {
defer ps.wg.Done()
t := time.NewTicker(1 * time.Second)
for {
select {
case <-ps.closing:
t.Stop()
select {
case <-t.C:
default:
}
return
case now := <-t.C:
ps.setClock(now.UnixNano())
}
}
}()
return ps, nil return ps, nil
} }
@ -118,11 +138,22 @@ type swarm struct {
type peerStore struct { type peerStore struct {
shards []*peerShard shards []*peerShard
closing chan struct{} closing chan struct{}
wg sync.WaitGroup // clock stores the current time nanoseconds, updated every second.
// Must be accessed atomically!
clock int64
wg sync.WaitGroup
} }
var _ storage.PeerStore = &peerStore{} var _ storage.PeerStore = &peerStore{}
func (ps *peerStore) getClock() int64 {
return atomic.LoadInt64(&ps.clock)
}
func (ps *peerStore) setClock(to int64) {
atomic.StoreInt64(&ps.clock, to)
}
func (ps *peerStore) shardIndex(infoHash bittorrent.InfoHash, af bittorrent.AddressFamily) uint32 { func (ps *peerStore) shardIndex(infoHash bittorrent.InfoHash, af bittorrent.AddressFamily) uint32 {
// There are twice the amount of shards specified by the user, the first // There are twice the amount of shards specified by the user, the first
// half is dedicated to IPv4 swarms and the second half is dedicated to // half is dedicated to IPv4 swarms and the second half is dedicated to
@ -181,7 +212,7 @@ func (ps *peerStore) PutSeeder(ih bittorrent.InfoHash, p bittorrent.Peer) error
recordInfohashesDelta(1) recordInfohashesDelta(1)
} }
shard.swarms[ih].seeders[pk] = time.Now().UnixNano() shard.swarms[ih].seeders[pk] = ps.getClock()
shard.Unlock() shard.Unlock()
return nil return nil
@ -240,7 +271,7 @@ func (ps *peerStore) PutLeecher(ih bittorrent.InfoHash, p bittorrent.Peer) error
recordInfohashesDelta(1) recordInfohashesDelta(1)
} }
shard.swarms[ih].leechers[pk] = time.Now().UnixNano() shard.swarms[ih].leechers[pk] = ps.getClock()
shard.Unlock() shard.Unlock()
return nil return nil
@ -301,7 +332,7 @@ func (ps *peerStore) GraduateLeecher(ih bittorrent.InfoHash, p bittorrent.Peer)
delete(shard.swarms[ih].leechers, pk) delete(shard.swarms[ih].leechers, pk)
shard.swarms[ih].seeders[pk] = time.Now().UnixNano() shard.swarms[ih].seeders[pk] = ps.getClock()
shard.Unlock() shard.Unlock()
return nil return nil