mirror of
https://github.com/libp2p/go-libp2p-peerstore.git
synced 2025-03-13 11:30:09 +08:00
segmented protocol info
This commit is contained in:
parent
303b1b6207
commit
ea23986270
145
peerstore.go
145
peerstore.go
@ -10,8 +10,38 @@ import (
|
|||||||
|
|
||||||
var _ Peerstore = (*peerstore)(nil)
|
var _ Peerstore = (*peerstore)(nil)
|
||||||
|
|
||||||
const maxInternedProtocols = 512
|
const maxInternedProtocols = 64
|
||||||
const maxInternedProtocolSize = 256
|
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 {
|
type peerstore struct {
|
||||||
Metrics
|
Metrics
|
||||||
@ -20,20 +50,27 @@ type peerstore struct {
|
|||||||
AddrBook
|
AddrBook
|
||||||
PeerMetadata
|
PeerMetadata
|
||||||
|
|
||||||
// lock for protocol information, separate from datastore lock
|
// segments for protocol information
|
||||||
protolock sync.RWMutex
|
segments segments
|
||||||
internedProtocols map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeerstore creates a data structure that stores peer data, backed by the
|
// NewPeerstore creates a data structure that stores peer data, backed by the
|
||||||
// supplied implementations of KeyBook, AddrBook and PeerMetadata.
|
// supplied implementations of KeyBook, AddrBook and PeerMetadata.
|
||||||
func NewPeerstore(kb KeyBook, ab AddrBook, md PeerMetadata) Peerstore {
|
func NewPeerstore(kb KeyBook, ab AddrBook, md PeerMetadata) Peerstore {
|
||||||
return &peerstore{
|
return &peerstore{
|
||||||
KeyBook: kb,
|
KeyBook: kb,
|
||||||
AddrBook: ab,
|
AddrBook: ab,
|
||||||
PeerMetadata: md,
|
PeerMetadata: md,
|
||||||
Metrics: NewMetrics(),
|
Metrics: NewMetrics(),
|
||||||
internedProtocols: make(map[string]string),
|
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
|
||||||
|
}(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,77 +117,46 @@ 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 {
|
func (ps *peerstore) SetProtocols(p peer.ID, protos ...string) error {
|
||||||
ps.protolock.Lock()
|
s := ps.segments.get(p)
|
||||||
defer ps.protolock.Unlock()
|
s.lk.Lock()
|
||||||
|
defer s.lk.Unlock()
|
||||||
|
|
||||||
protomap := make(map[string]struct{}, len(protos))
|
newprotos := make(map[string]struct{}, len(protos))
|
||||||
for _, proto := range protos {
|
for _, proto := range protos {
|
||||||
protomap[ps.internProtocol(proto)] = struct{}{}
|
newprotos[s.internProtocol(proto)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ps.Put(p, "protocols", protomap)
|
s.protocols[p] = newprotos
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peerstore) AddProtocols(p peer.ID, protos ...string) error {
|
func (ps *peerstore) AddProtocols(p peer.ID, protos ...string) error {
|
||||||
ps.protolock.Lock()
|
s := ps.segments.get(p)
|
||||||
defer ps.protolock.Unlock()
|
s.lk.Lock()
|
||||||
protomap, err := ps.getProtocolMap(p)
|
defer s.lk.Unlock()
|
||||||
if err != nil {
|
|
||||||
return err
|
protomap, ok := s.protocols[p]
|
||||||
|
if !ok {
|
||||||
|
protomap = make(map[string]struct{})
|
||||||
|
s.protocols[p] = protomap
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, proto := range protos {
|
for _, proto := range protos {
|
||||||
protomap[ps.internProtocol(proto)] = struct{}{}
|
protomap[s.internProtocol(proto)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ps.Put(p, "protocols", protomap)
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func (ps *peerstore) getProtocolMap(p peer.ID) (map[string]struct{}, error) {
|
|
||||||
iprotomap, err := ps.Get(p, "protocols")
|
|
||||||
switch err {
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
case ErrNotFound:
|
|
||||||
return make(map[string]struct{}), nil
|
|
||||||
case nil:
|
|
||||||
cast, ok := iprotomap.(map[string]struct{})
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("stored protocol set was not a map")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cast, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) {
|
func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) {
|
||||||
ps.protolock.RLock()
|
s := ps.segments.get(p)
|
||||||
defer ps.protolock.RUnlock()
|
s.lk.RLock()
|
||||||
pmap, err := ps.getProtocolMap(p)
|
defer s.lk.RUnlock()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]string, 0, len(pmap))
|
out := make([]string, 0, len(s.protocols))
|
||||||
for k := range pmap {
|
for k := range s.protocols[p] {
|
||||||
out = append(out, k)
|
out = append(out, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,16 +164,13 @@ func (ps *peerstore) GetProtocols(p peer.ID) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peerstore) SupportsProtocols(p peer.ID, protos ...string) ([]string, error) {
|
func (ps *peerstore) SupportsProtocols(p peer.ID, protos ...string) ([]string, error) {
|
||||||
ps.protolock.RLock()
|
s := ps.segments.get(p)
|
||||||
defer ps.protolock.RUnlock()
|
s.lk.RLock()
|
||||||
pmap, err := ps.getProtocolMap(p)
|
defer s.lk.RUnlock()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]string, 0, len(protos))
|
out := make([]string, 0, len(protos))
|
||||||
for _, proto := range protos {
|
for _, proto := range protos {
|
||||||
if _, ok := pmap[proto]; ok {
|
if _, ok := s.protocols[p][proto]; ok {
|
||||||
out = append(out, proto)
|
out = append(out, proto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user