From b637498cafd2bc8f90f9742ee2eafb19c2f88f37 Mon Sep 17 00:00:00 2001 From: Cole Brown Date: Tue, 5 Jun 2018 02:18:23 -0400 Subject: [PATCH] WIP: Begin work on a native badger peerstore --- addrmanager_badger.go | 130 ++++++++++++++++++++++++++++++++++++++++++ peerstore_badger.go | 91 +++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 addrmanager_badger.go create mode 100644 peerstore_badger.go diff --git a/addrmanager_badger.go b/addrmanager_badger.go new file mode 100644 index 0000000..55ebbec --- /dev/null +++ b/addrmanager_badger.go @@ -0,0 +1,130 @@ +package peerstore + +import ( + "context" + "time" + + "github.com/libp2p/go-libp2p-peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/hashicorp/golang-lru" + "github.com/dgraph-io/badger" + "github.com/multiformats/go-multihash" + "encoding/gob" + "bytes" + "encoding/binary" +) + +type addrmanager_badger struct { + cache *lru.Cache + db *badger.DB +} + +type addrentry struct { + Addr []byte + TTL time.Duration +} + +func (mgr *addrmanager_badger) AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) { + mgr.AddAddrs(p, []ma.Multiaddr{addr}, ttl) +} + +// use murmur3 because it's the most compact +func hashMultiaddr(addr *ma.Multiaddr) ([]byte, error) { + return multihash.Encode((*addr).Bytes(), multihash.MURMUR3) +} + +// not relevant w/ key prefixing +func createAddrEntry(addr ma.Multiaddr, ttl time.Duration) ([]byte, error) { + entry := addrentry{Addr: addr.Bytes(), TTL: ttl} + buf := bytes.Buffer{} + enc := gob.NewEncoder(&buf) + if err := enc.Encode(entry); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func createKeyPrefix(p *peer.ID, ttl time.Duration) ([]byte, error) { + buf := bytes.NewBufferString(string(*p)) + if err := binary.Write(buf, binary.LittleEndian, ttl); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func createUniqueKey(p *peer.ID, addr *ma.Multiaddr, ttl time.Duration) ([]byte, error) { + prefix, err := createKeyPrefix(p, ttl) + if err != nil { + return nil, err + } + addrHash, err := hashMultiaddr(addr) + if err != nil { + return nil, err + } + + return append(prefix, addrHash...), nil +} + +func (mgr *addrmanager_badger) AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) { + // if ttl is zero, exit. nothing to do. + if ttl <= 0 { + log.Debugf("short circuiting AddAddrs with ttl %d", ttl) + return + } + + txn := mgr.db.NewTransaction(true) + defer txn.Discard() + + for _, addr := range addrs { + key, err := createUniqueKey(&p, &addr, ttl) + if err != nil { + log.Error(err) + return + } + txn.SetWithTTL(key, addr.Bytes(), ttl) + } + + txn.Commit(func (err error) { + log.Error(err) + }) +} + +func (mgr *addrmanager_badger) SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration) { + mgr.AddAddr(p, addr, ttl) +} + +func (mgr *addrmanager_badger) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration) { + mgr.AddAddrs(p, addrs, ttl) +} + +func (mgr *addrmanager_badger) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) { + prefix, err := createKeyPrefix(&p, oldTTL) + if err != nil { + log.Error(err) + } + txn := mgr.db.NewTransaction(true) + opts := badger.DefaultIteratorOptions + iter := txn.NewIterator(opts) + + iter.Seek(prefix) + for iter.Valid() && iter.ValidForPrefix(prefix) { + item := iter.Item() + // TODO: + + iter.Next() + } + +} + +func (mgr *addrmanager_badger) Addrs(p peer.ID) []ma.Multiaddr { + panic("implement me") +} + +func (mgr *addrmanager_badger) AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr { + panic("implement me") +} + +func (mgr *addrmanager_badger) ClearAddrs(p peer.ID) { + panic("implement me") +} diff --git a/peerstore_badger.go b/peerstore_badger.go new file mode 100644 index 0000000..49dad24 --- /dev/null +++ b/peerstore_badger.go @@ -0,0 +1,91 @@ +package peerstore + +import ( + "github.com/dgraph-io/badger" + "github.com/libp2p/go-libp2p-crypto" + "time" + "github.com/libp2p/go-libp2p-peer" +) + +type keybook_badger struct { + +} + +func (kb *keybook_badger) PubKey(peer.ID) crypto.PubKey { + panic("implement me") +} + +func (kb *keybook_badger) AddPubKey(peer.ID, crypto.PubKey) error { + panic("implement me") +} + +func (kb *keybook_badger) PrivKey(peer.ID) crypto.PrivKey { + panic("implement me") +} + +func (kb *keybook_badger) AddPrivKey(peer.ID, crypto.PrivKey) error { + panic("implement me") +} + +type peerstore_badger struct { + *addrmanager_badger + *keybook_badger + *badger.DB +} + +func (store *peerstore_badger) PubKey(peer.ID) crypto.PubKey { + panic("implement me") +} + +func (store *peerstore_badger) AddPubKey(peer.ID, crypto.PubKey) error { + panic("implement me") +} + +func (store *peerstore_badger) PrivKey(peer.ID) crypto.PrivKey { + panic("implement me") +} + +func (store *peerstore_badger) AddPrivKey(peer.ID, crypto.PrivKey) error { + panic("implement me") +} + +func (store *peerstore_badger) RecordLatency(peer.ID, time.Duration) { + panic("implement me") +} + +func (store *peerstore_badger) LatencyEWMA(peer.ID) time.Duration { + panic("implement me") +} + +func (store *peerstore_badger) Peers() []peer.ID { + panic("implement me") +} + +func (store *peerstore_badger) PeerInfo(peer.ID) PeerInfo { + panic("implement me") +} + +func (store *peerstore_badger) Get(id peer.ID, key string) (interface{}, error) { + panic("implement me") +} + +func (store *peerstore_badger) Put(id peer.ID, key string, val interface{}) error { + panic("implement me") +} + +func (store *peerstore_badger) GetProtocols(peer.ID) ([]string, error) { + panic("implement me") +} + +func (store *peerstore_badger) AddProtocols(peer.ID, ...string) error { + panic("implement me") +} + +func (store *peerstore_badger) SetProtocols(peer.ID, ...string) error { + panic("implement me") +} + +func (store *peerstore_badger) SupportsProtocols(peer.ID, ...string) ([]string, error) { + panic("implement me") +} +