2018-09-02 19:03:02 +08:00
|
|
|
package pstoreds
|
2018-08-29 22:12:41 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
2018-10-04 17:51:57 +08:00
|
|
|
base32 "github.com/whyrusleeping/base32"
|
|
|
|
|
2018-09-08 01:46:23 +08:00
|
|
|
ds "github.com/ipfs/go-datastore"
|
2018-09-28 21:18:05 +08:00
|
|
|
query "github.com/ipfs/go-datastore/query"
|
2018-08-30 23:24:09 +08:00
|
|
|
|
2018-09-28 21:18:05 +08:00
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
2018-08-29 22:12:41 +08:00
|
|
|
pstore "github.com/libp2p/go-libp2p-peerstore"
|
|
|
|
)
|
|
|
|
|
2018-09-04 18:34:55 +08:00
|
|
|
// Configuration object for the peerstore.
|
2018-09-12 20:44:14 +08:00
|
|
|
type Options struct {
|
2018-09-04 18:34:55 +08:00
|
|
|
// The size of the in-memory cache. A value of 0 or lower disables the cache.
|
|
|
|
CacheSize uint
|
|
|
|
|
2018-11-13 06:28:12 +08:00
|
|
|
// Sweep interval to purge expired addresses from the datastore.
|
|
|
|
GCInterval time.Duration
|
2018-09-04 18:34:55 +08:00
|
|
|
|
|
|
|
// Number of times to retry transactional writes.
|
|
|
|
WriteRetries uint
|
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultOpts returns the default options for a persistent peerstore:
|
|
|
|
// * Cache size: 1024
|
|
|
|
// * TTL sweep interval: 1 second
|
|
|
|
// * WriteRetries: 5
|
2018-09-12 20:44:14 +08:00
|
|
|
func DefaultOpts() Options {
|
|
|
|
return Options{
|
2018-09-04 18:34:55 +08:00
|
|
|
CacheSize: 1024,
|
2018-11-13 06:28:12 +08:00
|
|
|
GCInterval: 5 * time.Minute,
|
2018-09-04 18:34:55 +08:00
|
|
|
WriteRetries: 5,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 22:12:41 +08:00
|
|
|
// NewPeerstore creates a peerstore backed by the provided persistent datastore.
|
2018-09-12 20:44:14 +08:00
|
|
|
func NewPeerstore(ctx context.Context, store ds.TxnDatastore, opts Options) (pstore.Peerstore, error) {
|
2018-09-11 21:13:14 +08:00
|
|
|
addrBook, err := NewAddrBook(ctx, store, opts)
|
2018-08-29 22:12:41 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-28 21:04:52 +08:00
|
|
|
keyBook, err := NewKeyBook(ctx, store, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
peerMetadata, err := NewPeerMetadata(ctx, store, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ps := pstore.NewPeerstore(keyBook, addrBook, peerMetadata)
|
2018-08-29 22:12:41 +08:00
|
|
|
return ps, nil
|
|
|
|
}
|
2018-09-28 21:04:52 +08:00
|
|
|
|
|
|
|
// uniquePeerIds extracts and returns unique peer IDs from database keys.
|
|
|
|
func uniquePeerIds(ds ds.TxnDatastore, prefix ds.Key, extractor func(result query.Result) string) (peer.IDSlice, error) {
|
|
|
|
var (
|
|
|
|
q = query.Query{Prefix: prefix.String(), KeysOnly: true}
|
|
|
|
results query.Results
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
txn, err := ds.NewTransaction(true)
|
|
|
|
if err != nil {
|
2018-09-29 01:47:41 +08:00
|
|
|
return nil, err
|
2018-09-28 21:04:52 +08:00
|
|
|
}
|
|
|
|
defer txn.Discard()
|
|
|
|
|
|
|
|
if results, err = txn.Query(q); err != nil {
|
|
|
|
log.Error(err)
|
2018-09-29 01:47:41 +08:00
|
|
|
return nil, err
|
2018-09-28 21:04:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
defer results.Close()
|
|
|
|
|
|
|
|
idset := make(map[string]struct{})
|
|
|
|
for result := range results.Next() {
|
|
|
|
k := extractor(result)
|
|
|
|
idset[k] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(idset) == 0 {
|
|
|
|
return peer.IDSlice{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ids := make(peer.IDSlice, len(idset))
|
|
|
|
i := 0
|
|
|
|
for id := range idset {
|
2018-10-04 17:51:57 +08:00
|
|
|
pid, _ := base32.RawStdEncoding.DecodeString(id)
|
|
|
|
ids[i], _ = peer.IDFromBytes(pid)
|
2018-09-28 21:04:52 +08:00
|
|
|
i++
|
|
|
|
}
|
|
|
|
return ids, nil
|
|
|
|
}
|