34fdc329fc
This is the third implementation attempt. This time, rather than broadcasting PeerAdd/Join requests to the whole cluster, we use the consensus log to broadcast new peers joining. This makes it easier to recover from errors and to know who exactly is member of a cluster and who is not. The consensus is, after all, meant to agree on things, and the list of cluster peers is something everyone has to agree on. Raft itself uses a special log operation to maintain the peer set. The tests are almost unchanged from the previous attempts so it should be the same, except it doesn't seem possible to bootstrap a bunch of nodes at the same time using different bootstrap nodes. It works when using the same. I'm not sure this worked before either, but the code is simpler than recursively contacting peers, and scales better for larger clusters. Nodes have to be careful about joining clusters while keeping the state from a different cluster (disjoint logs). This may cause problems with Raft. License: MIT Signed-off-by: Hector Sanjuan <hector@protocol.ai>
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package ipfscluster
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
host "github.com/libp2p/go-libp2p-host"
|
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
// The copy functions below are used in calls to Cluste.multiRPC()
|
|
// func copyPIDsToIfaces(in []peer.ID) []interface{} {
|
|
// ifaces := make([]interface{}, len(in), len(in))
|
|
// for i := range in {
|
|
// ifaces[i] = &in[i]
|
|
// }
|
|
// return ifaces
|
|
// }
|
|
|
|
func copyIDSerialsToIfaces(in []IDSerial) []interface{} {
|
|
ifaces := make([]interface{}, len(in), len(in))
|
|
for i := range in {
|
|
ifaces[i] = &in[i]
|
|
}
|
|
return ifaces
|
|
}
|
|
|
|
func copyPinInfoToIfaces(in []PinInfo) []interface{} {
|
|
ifaces := make([]interface{}, len(in), len(in))
|
|
for i := range in {
|
|
ifaces[i] = &in[i]
|
|
}
|
|
return ifaces
|
|
}
|
|
|
|
func copyPinInfoSliceToIfaces(in [][]PinInfo) []interface{} {
|
|
ifaces := make([]interface{}, len(in), len(in))
|
|
for i := range in {
|
|
ifaces[i] = &in[i]
|
|
}
|
|
return ifaces
|
|
}
|
|
|
|
func copyEmptyStructToIfaces(in []struct{}) []interface{} {
|
|
ifaces := make([]interface{}, len(in), len(in))
|
|
for i := range in {
|
|
ifaces[i] = &in[i]
|
|
}
|
|
return ifaces
|
|
}
|
|
|
|
func multiaddrSplit(addr ma.Multiaddr) (peer.ID, ma.Multiaddr, error) {
|
|
pid, err := addr.ValueForProtocol(ma.P_IPFS)
|
|
if err != nil {
|
|
err = fmt.Errorf("invalid peer multiaddress: %s: %s", addr, err)
|
|
logger.Error(err)
|
|
return "", nil, err
|
|
}
|
|
|
|
ipfs, _ := ma.NewMultiaddr("/ipfs/" + pid)
|
|
decapAddr := addr.Decapsulate(ipfs)
|
|
|
|
peerID, err := peer.IDB58Decode(pid)
|
|
if err != nil {
|
|
err = fmt.Errorf("invalid peer ID in multiaddress: %s: %s", pid, err)
|
|
logger.Error(err)
|
|
return "", nil, err
|
|
}
|
|
return peerID, decapAddr, nil
|
|
}
|
|
|
|
func multiaddrJoin(addr ma.Multiaddr, p peer.ID) ma.Multiaddr {
|
|
pidAddr, err := ma.NewMultiaddr("/ipfs/" + peer.IDB58Encode(p))
|
|
// let this break badly
|
|
if err != nil {
|
|
panic("called multiaddrJoin with bad peer!")
|
|
}
|
|
return addr.Encapsulate(pidAddr)
|
|
}
|
|
|
|
func peersFromMultiaddrs(addrs []ma.Multiaddr) []peer.ID {
|
|
var pids []peer.ID
|
|
for _, addr := range addrs {
|
|
pid, _, err := multiaddrSplit(addr)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
pids = append(pids, pid)
|
|
}
|
|
return pids
|
|
}
|
|
|
|
// // connect to a peer ID.
|
|
// func connectToPeer(ctx context.Context, h host.Host, id peer.ID, addr ma.Multiaddr) error {
|
|
// err := h.Connect(ctx, peerstore.PeerInfo{
|
|
// ID: id,
|
|
// Addrs: []ma.Multiaddr{addr},
|
|
// })
|
|
// return err
|
|
// }
|
|
|
|
// // return the local multiaddresses used to communicate to a peer.
|
|
// func localMultiaddrsTo(h host.Host, pid peer.ID) []ma.Multiaddr {
|
|
// var addrs []ma.Multiaddr
|
|
// conns := h.Network().ConnsToPeer(pid)
|
|
// logger.Debugf("conns to %s are: %s", pid, conns)
|
|
// for _, conn := range conns {
|
|
// addrs = append(addrs, multiaddrJoin(conn.LocalMultiaddr(), h.ID()))
|
|
// }
|
|
// return addrs
|
|
// }
|
|
|
|
// If we have connections open to that PID and they are using a different addr
|
|
// then we return the one we are using, otherwise the one provided
|
|
func getRemoteMultiaddr(h host.Host, pid peer.ID, addr ma.Multiaddr) ma.Multiaddr {
|
|
conns := h.Network().ConnsToPeer(pid)
|
|
if len(conns) > 0 {
|
|
return multiaddrJoin(conns[0].RemoteMultiaddr(), pid)
|
|
}
|
|
return multiaddrJoin(addr, pid)
|
|
}
|