refactor protocol functionality into ProtoBook

This commit is contained in:
vyzo
2019-05-17 12:33:33 +03:00
parent ea23986270
commit 08caa87351
5 changed files with 144 additions and 120 deletions

View File

@@ -3,74 +3,30 @@ package peerstore
import (
"fmt"
"io"
"sync"
peer "github.com/libp2p/go-libp2p-peer"
)
var _ Peerstore = (*peerstore)(nil)
const maxInternedProtocols = 64
const maxInternedProtocolSize = 128
type segment struct {
lk sync.RWMutex
interned map[string]string
protocols map[peer.ID]map[string]struct{}
}
type segments [256]*segment
func (s *segments) get(id peer.ID) *segment {
b := []byte(id)
return s[b[len(b)-1]]
}
func (s *segment) internProtocol(proto string) string {
if len(proto) > maxInternedProtocolSize {
return proto
}
if interned, ok := s.interned[proto]; ok {
return interned
}
if len(s.interned) >= maxInternedProtocols {
s.interned = make(map[string]string, maxInternedProtocols)
}
s.interned[proto] = proto
return proto
}
type peerstore struct {
Metrics
KeyBook
AddrBook
ProtoBook
PeerMetadata
// segments for protocol information
segments segments
}
// 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 {
func NewPeerstore(kb KeyBook, ab AddrBook, pb ProtoBook, md PeerMetadata) Peerstore {
return &peerstore{
KeyBook: kb,
AddrBook: ab,
ProtoBook: pb,
PeerMetadata: md,
Metrics: NewMetrics(),
segments: func() (ret segments) {
for i := range ret {
ret[i] = &segment{
interned: make(map[string]string),
protocols: make(map[peer.ID]map[string]struct{}),
}
}
return ret
}(),
}
}
@@ -86,6 +42,7 @@ func (ps *peerstore) Close() (err error) {
weakClose("keybook", ps.KeyBook)
weakClose("addressbook", ps.AddrBook)
weakClose("protobook", ps.ProtoBook)
weakClose("peermetadata", ps.PeerMetadata)
if len(errs) > 0 {
@@ -117,67 +74,6 @@ func (ps *peerstore) PeerInfo(p peer.ID) PeerInfo {
}
}
func (ps *peerstore) SetProtocols(p peer.ID, protos ...string) error {
s := ps.segments.get(p)
s.lk.Lock()
defer s.lk.Unlock()
newprotos := make(map[string]struct{}, len(protos))
for _, proto := range protos {
newprotos[s.internProtocol(proto)] = struct{}{}
}
s.protocols[p] = newprotos
return nil
}
func (ps *peerstore) AddProtocols(p peer.ID, protos ...string) error {
s := ps.segments.get(p)
s.lk.Lock()
defer s.lk.Unlock()
protomap, ok := s.protocols[p]
if !ok {
protomap = make(map[string]struct{})
s.protocols[p] = protomap
}
for _, proto := range protos {
protomap[s.internProtocol(proto)] = struct{}{}
}
return nil
}
func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) {
s := ps.segments.get(p)
s.lk.RLock()
defer s.lk.RUnlock()
out := make([]string, 0, len(s.protocols))
for k := range s.protocols[p] {
out = append(out, k)
}
return out, nil
}
func (ps *peerstore) SupportsProtocols(p peer.ID, protos ...string) ([]string, error) {
s := ps.segments.get(p)
s.lk.RLock()
defer s.lk.RUnlock()
out := make([]string, 0, len(protos))
for _, proto := range protos {
if _, ok := s.protocols[p][proto]; ok {
out = append(out, proto)
}
}
return out, nil
}
func PeerInfos(ps Peerstore, peers peer.IDSlice) []PeerInfo {
pi := make([]PeerInfo, len(peers))
for i, p := range peers {