From b65b48dbe1954146292d4de83dbd10f12eb3115a Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 23 Apr 2019 00:54:18 -0700 Subject: [PATCH] intern protocol names Ideally, we'd store a bitmap. But we'll have to think through how we want that to play out with the datastore-backed peerstore (maybe move the `*Protocols` methods down to the backend implementation?). --- peerstore.go | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/peerstore.go b/peerstore.go index 40411fb..29e0c67 100644 --- a/peerstore.go +++ b/peerstore.go @@ -10,6 +10,9 @@ import ( var _ Peerstore = (*peerstore)(nil) +const maxInternedProtocols = 256 +const maxInternedProtocolSize = 96 + type peerstore struct { Metrics @@ -18,17 +21,19 @@ type peerstore struct { PeerMetadata // lock for protocol information, separate from datastore lock - protolock sync.Mutex + protolock sync.Mutex + internedProtocols map[string]string } // NewPeerstore creates a data structure that stores peer data, backed by the // supplied implementations of KeyBook, AddrBook and PeerMetadata. func NewPeerstore(kb KeyBook, ab AddrBook, md PeerMetadata) Peerstore { return &peerstore{ - KeyBook: kb, - AddrBook: ab, - PeerMetadata: md, - Metrics: NewMetrics(), + KeyBook: kb, + AddrBook: ab, + PeerMetadata: md, + Metrics: NewMetrics(), + internedProtocols: make(map[string]string), } } @@ -75,13 +80,30 @@ func (ps *peerstore) PeerInfo(p peer.ID) PeerInfo { } } +func (ps *peerstore) internProtocol(s string) string { + if len(s) > maxInternedProtocolSize { + return s + } + + if interned, ok := ps.internedProtocols[s]; ok { + return interned + } + + if len(ps.internedProtocols) >= maxInternedProtocols { + ps.internedProtocols = make(map[string]string, maxInternedProtocols) + } + + ps.internedProtocols[s] = s + return s +} + func (ps *peerstore) SetProtocols(p peer.ID, protos ...string) error { ps.protolock.Lock() defer ps.protolock.Unlock() - protomap := make(map[string]struct{}) + protomap := make(map[string]struct{}, len(protos)) for _, proto := range protos { - protomap[proto] = struct{}{} + protomap[ps.internProtocol(proto)] = struct{}{} } return ps.Put(p, "protocols", protomap) @@ -96,7 +118,7 @@ func (ps *peerstore) AddProtocols(p peer.ID, protos ...string) error { } for _, proto := range protos { - protomap[proto] = struct{}{} + protomap[ps.internProtocol(proto)] = struct{}{} } return ps.Put(p, "protocols", protomap) @@ -127,8 +149,8 @@ func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) { return nil, err } - var out []string - for k, _ := range pmap { + out := make([]string, 0, len(pmap)) + for k := range pmap { out = append(out, k) } @@ -143,7 +165,7 @@ func (ps *peerstore) SupportsProtocols(p peer.ID, protos ...string) ([]string, e return nil, err } - var out []string + out := make([]string, 0, len(protos)) for _, proto := range protos { if _, ok := pmap[proto]; ok { out = append(out, proto)