diff options
| author | Mikio Hara <mikioh.mikioh@gmail.com> | 2016-04-13 06:19:53 +0900 |
|---|---|---|
| committer | Mikio Hara <mikioh.mikioh@gmail.com> | 2016-04-15 01:45:27 +0000 |
| commit | 1d214f7062e80bebb081cdfad2ceda3e5bd0de29 (patch) | |
| tree | 5258186a65107b879efe4831d51c4e3b0c70dd72 /src/net/interface.go | |
| parent | 19db74566491dcbb4dc2ad0a92b98aa2c28dd8fe (diff) | |
| download | go-1d214f7062e80bebb081cdfad2ceda3e5bd0de29.tar.xz | |
net: cache IPv6 zone information for applications using IPv6 link-local address
This change reduces the overhead of calling routing information per IPv6
link-local datagram read by caching IPv6 addressing scope zone
information.
Fixes #15237.
name old time/op new time/op delta
UDP6LinkLocalUnicast-8 64.9µs ± 0% 18.6µs ± 0% -71.30%
name old alloc/op new alloc/op delta
UDP6LinkLocalUnicast-8 11.2kB ± 0% 0.2kB ± 0% -98.42%
name old allocs/op new allocs/op delta
UDP6LinkLocalUnicast-8 101 ± 0% 3 ± 0% -97.03%
Change-Id: I5ae2ef5058df1028bbb7f4ab32b13edfb330c3a7
Reviewed-on: https://go-review.googlesource.com/21952
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/net/interface.go')
| -rw-r--r-- | src/net/interface.go | 81 |
1 files changed, 78 insertions, 3 deletions
diff --git a/src/net/interface.go b/src/net/interface.go index c99f8fd216..52b857c65f 100644 --- a/src/net/interface.go +++ b/src/net/interface.go @@ -4,7 +4,11 @@ package net -import "errors" +import ( + "errors" + "sync" + "time" +) var ( errInvalidInterface = errors.New("invalid network interface") @@ -88,9 +92,12 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) { func Interfaces() ([]Interface, error) { ift, err := interfaceTable(0) if err != nil { - err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } - return ift, err + if len(ift) != 0 { + zoneCache.update(ift) + } + return ift, nil } // InterfaceAddrs returns a list of the system's network interface @@ -137,6 +144,9 @@ func InterfaceByName(name string) (*Interface, error) { if err != nil { return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } + if len(ift) != 0 { + zoneCache.update(ift) + } for _, ifi := range ift { if name == ifi.Name { return &ifi, nil @@ -144,3 +154,68 @@ func InterfaceByName(name string) (*Interface, error) { } return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface} } + +// An ipv6ZoneCache represents a cache holding partial network +// interface information. It is used for reducing the cost of IPv6 +// addressing scope zone resolution. +type ipv6ZoneCache struct { + sync.RWMutex // guard the following + lastFetched time.Time // last time routing information was fetched + toIndex map[string]int // interface name to its index + toName map[int]string // interface index to its name +} + +var zoneCache = ipv6ZoneCache{ + toIndex: make(map[string]int), + toName: make(map[int]string), +} + +func (zc *ipv6ZoneCache) update(ift []Interface) { + zc.Lock() + defer zc.Unlock() + now := time.Now() + if zc.lastFetched.After(now.Add(-60 * time.Second)) { + return + } + zc.lastFetched = now + if len(ift) == 0 { + var err error + if ift, err = interfaceTable(0); err != nil { + return + } + } + zc.toIndex = make(map[string]int, len(ift)) + zc.toName = make(map[int]string, len(ift)) + for _, ifi := range ift { + zc.toIndex[ifi.Name] = ifi.Index + zc.toName[ifi.Index] = ifi.Name + } +} + +func zoneToString(zone int) string { + if zone == 0 { + return "" + } + zoneCache.update(nil) + zoneCache.RLock() + defer zoneCache.RUnlock() + name, ok := zoneCache.toName[zone] + if !ok { + name = uitoa(uint(zone)) + } + return name +} + +func zoneToInt(zone string) int { + if zone == "" { + return 0 + } + zoneCache.update(nil) + zoneCache.RLock() + defer zoneCache.RUnlock() + index, ok := zoneCache.toIndex[zone] + if !ok { + index, _, _ = dtoi(zone, 0) + } + return index +} |
