Commit cfdf01d5 authored by Jeromy's avatar Jeromy

bitswap first working commit!

parent 678db4fa
...@@ -67,6 +67,7 @@ func NewBitSwap(p *peer.Peer, net swarm.Network, d ds.Datastore, r routing.IpfsR ...@@ -67,6 +67,7 @@ func NewBitSwap(p *peer.Peer, net swarm.Network, d ds.Datastore, r routing.IpfsR
routing: r.(*dht.IpfsDHT), routing: r.(*dht.IpfsDHT),
meschan: net.GetChannel(swarm.PBWrapper_BITSWAP), meschan: net.GetChannel(swarm.PBWrapper_BITSWAP),
haltChan: make(chan struct{}), haltChan: make(chan struct{}),
listener: swarm.NewMesListener(),
} }
go bs.handleMessages() go bs.handleMessages()
...@@ -90,7 +91,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) ( ...@@ -90,7 +91,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) (
ledger := bs.GetLedger(pr.Key()) ledger := bs.GetLedger(pr.Key())
blk, err := bs.getBlock(k, pr, tleft) blk, err := bs.getBlock(k, pr, tleft)
if err != nil { if err != nil {
u.PErr("%v\n", err) u.PErr("getBlock returned: %v\n", err)
return return
} }
// NOTE: this credits everyone who sends us a block, // NOTE: this credits everyone who sends us a block,
...@@ -106,6 +107,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) ( ...@@ -106,6 +107,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) (
select { select {
case blkdata := <-valchan: case blkdata := <-valchan:
close(valchan)
return blocks.NewBlock(blkdata) return blocks.NewBlock(blkdata)
case <-after: case <-after:
return nil, u.ErrTimeout return nil, u.ErrTimeout
...@@ -113,6 +115,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) ( ...@@ -113,6 +115,7 @@ func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) (
} }
func (bs *BitSwap) getBlock(k u.Key, p *peer.Peer, timeout time.Duration) ([]byte, error) { func (bs *BitSwap) getBlock(k u.Key, p *peer.Peer, timeout time.Duration) ([]byte, error) {
u.DOut("[%s] getBlock '%s' from [%s]\n", bs.peer.ID.Pretty(), k.Pretty(), p.ID.Pretty())
// //
mes := new(PBMessage) mes := new(PBMessage)
mes.Id = proto.Uint64(swarm.GenerateMessageID()) mes.Id = proto.Uint64(swarm.GenerateMessageID())
...@@ -161,6 +164,7 @@ func (bs *BitSwap) handleMessages() { ...@@ -161,6 +164,7 @@ func (bs *BitSwap) handleMessages() {
} }
if pmes.GetResponse() { if pmes.GetResponse() {
bs.listener.Respond(pmes.GetId(), mes) bs.listener.Respond(pmes.GetId(), mes)
continue
} }
switch pmes.GetType() { switch pmes.GetType() {
...@@ -176,16 +180,20 @@ func (bs *BitSwap) handleMessages() { ...@@ -176,16 +180,20 @@ func (bs *BitSwap) handleMessages() {
} }
func (bs *BitSwap) handleGetBlock(p *peer.Peer, pmes *PBMessage) { func (bs *BitSwap) handleGetBlock(p *peer.Peer, pmes *PBMessage) {
u.DOut("handleGetBlock.\n")
ledger := bs.GetLedger(p.Key()) ledger := bs.GetLedger(p.Key())
u.DOut("finding [%s] in datastore.\n", u.Key(pmes.GetKey()).Pretty())
idata, err := bs.datastore.Get(ds.NewKey(pmes.GetKey())) idata, err := bs.datastore.Get(ds.NewKey(pmes.GetKey()))
if err != nil { if err != nil {
u.PErr("handleGetBlock datastore returned: %v\n", err)
if err == ds.ErrNotFound { if err == ds.ErrNotFound {
return return
} }
u.PErr("%v\n", err)
return return
} }
u.DOut("found value!\n")
data, ok := idata.([]byte) data, ok := idata.([]byte)
if !ok { if !ok {
u.PErr("Failed casting data from datastore.") u.PErr("Failed casting data from datastore.")
...@@ -193,13 +201,18 @@ func (bs *BitSwap) handleGetBlock(p *peer.Peer, pmes *PBMessage) { ...@@ -193,13 +201,18 @@ func (bs *BitSwap) handleGetBlock(p *peer.Peer, pmes *PBMessage) {
} }
if ledger.ShouldSend() { if ledger.ShouldSend() {
u.DOut("Sending value back!\n")
resp := &Message{ resp := &Message{
Value: data, Value: data,
Response: true, Response: true,
ID: pmes.GetId(), ID: pmes.GetId(),
Type: PBMessage_GET_BLOCK,
Success: true,
} }
bs.meschan.Outgoing <- swarm.NewMessage(p, resp.ToProtobuf()) bs.meschan.Outgoing <- swarm.NewMessage(p, resp.ToProtobuf())
ledger.SentBytes(uint64(len(data))) ledger.SentBytes(uint64(len(data)))
} else {
u.DOut("Ledger decided not to send anything...\n")
} }
} }
...@@ -210,6 +223,7 @@ func (bs *BitSwap) GetLedger(k u.Key) *Ledger { ...@@ -210,6 +223,7 @@ func (bs *BitSwap) GetLedger(k u.Key) *Ledger {
} }
l = new(Ledger) l = new(Ledger)
l.Strategy = StandardStrategy
l.Partner = peer.ID(k) l.Partner = peer.ID(k)
bs.partners[k] = l bs.partners[k] = l
return l return l
......
package bitswap package bitswap
import ( import (
"math/rand"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
u "github.com/jbenet/go-ipfs/util" u "github.com/jbenet/go-ipfs/util"
...@@ -26,13 +24,15 @@ type Ledger struct { ...@@ -26,13 +24,15 @@ type Ledger struct {
// WantList is a (bounded, small) set of keys that Partner desires. // WantList is a (bounded, small) set of keys that Partner desires.
WantList KeySet WantList KeySet
Strategy StrategyFunc
} }
// LedgerMap lists Ledgers by their Partner key. // LedgerMap lists Ledgers by their Partner key.
type LedgerMap map[u.Key]*Ledger type LedgerMap map[u.Key]*Ledger
func (l *Ledger) ShouldSend() bool { func (l *Ledger) ShouldSend() bool {
return rand.Float64() <= probabilitySend(l.Accounting.Value()) return l.Strategy(l.Accounting)
} }
func (l *Ledger) SentBytes(n uint64) { func (l *Ledger) SentBytes(n uint64) {
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
) )
type Message struct { type Message struct {
Type PBMessage_MessageType
ID uint64 ID uint64
Response bool Response bool
Key u.Key Key u.Key
...@@ -16,6 +17,7 @@ type Message struct { ...@@ -16,6 +17,7 @@ type Message struct {
func (m *Message) ToProtobuf() *PBMessage { func (m *Message) ToProtobuf() *PBMessage {
pmes := new(PBMessage) pmes := new(PBMessage)
pmes.Id = &m.ID pmes.Id = &m.ID
pmes.Type = &m.Type
if m.Response { if m.Response {
pmes.Response = proto.Bool(true) pmes.Response = proto.Bool(true)
} }
......
...@@ -2,8 +2,19 @@ package bitswap ...@@ -2,8 +2,19 @@ package bitswap
import ( import (
"math" "math"
"math/rand"
) )
type StrategyFunc func(debtRatio) bool
func StandardStrategy(db debtRatio) bool {
return rand.Float64() <= probabilitySend(db.Value())
}
func YesManStrategy(db debtRatio) bool {
return true
}
func probabilitySend(ratio float64) float64 { func probabilitySend(ratio float64) float64 {
x := 1 + math.Exp(6-3*ratio) x := 1 + math.Exp(6-3*ratio)
y := 1 / x y := 1 / x
......
...@@ -2,6 +2,7 @@ package blockservice ...@@ -2,6 +2,7 @@ package blockservice
import ( import (
"fmt" "fmt"
"time"
ds "github.com/jbenet/datastore.go" ds "github.com/jbenet/datastore.go"
bitswap "github.com/jbenet/go-ipfs/bitswap" bitswap "github.com/jbenet/go-ipfs/bitswap"
...@@ -19,18 +20,27 @@ type BlockService struct { ...@@ -19,18 +20,27 @@ type BlockService struct {
} }
// NewBlockService creates a BlockService with given datastore instance. // NewBlockService creates a BlockService with given datastore instance.
func NewBlockService(d ds.Datastore) (*BlockService, error) { func NewBlockService(d ds.Datastore, rem *bitswap.BitSwap) (*BlockService, error) {
if d == nil { if d == nil {
return nil, fmt.Errorf("BlockService requires valid datastore") return nil, fmt.Errorf("BlockService requires valid datastore")
} }
return &BlockService{Datastore: d}, nil if rem == nil {
return nil, fmt.Errorf("BlockService requires a valid bitswap")
}
return &BlockService{Datastore: d, Remote: rem}, nil
} }
// AddBlock adds a particular block to the service, Putting it into the datastore. // AddBlock adds a particular block to the service, Putting it into the datastore.
func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) { func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) {
k := b.Key() k := b.Key()
dsk := ds.NewKey(string(k)) dsk := ds.NewKey(string(k))
return k, s.Datastore.Put(dsk, b.Data) u.DOut("storing [%s] in datastore\n", k.Pretty())
err := s.Datastore.Put(dsk, b.Data)
if err != nil {
return k, err
}
err = s.Remote.HaveBlock(b.Key())
return k, err
} }
// GetBlock retrieves a particular block from the service, // GetBlock retrieves a particular block from the service,
...@@ -38,17 +48,22 @@ func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) { ...@@ -38,17 +48,22 @@ func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) {
func (s *BlockService) GetBlock(k u.Key) (*blocks.Block, error) { func (s *BlockService) GetBlock(k u.Key) (*blocks.Block, error) {
dsk := ds.NewKey(string(k)) dsk := ds.NewKey(string(k))
datai, err := s.Datastore.Get(dsk) datai, err := s.Datastore.Get(dsk)
if err != nil { if err == nil {
return nil, err bdata, ok := datai.([]byte)
if !ok {
return nil, fmt.Errorf("data associated with %s is not a []byte", k)
}
return &blocks.Block{
Multihash: mh.Multihash(k),
Data: bdata,
}, nil
} else if err == ds.ErrNotFound {
blk, err := s.Remote.GetBlock(k, time.Second*5)
if err != nil {
return nil, err
}
return blk, nil
} else {
return nil, u.ErrNotFound
} }
data, ok := datai.([]byte)
if !ok {
return nil, fmt.Errorf("data associated with %s is not a []byte", k)
}
return &blocks.Block{
Multihash: mh.Multihash(k),
Data: data,
}, nil
} }
...@@ -59,7 +59,7 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) { ...@@ -59,7 +59,7 @@ func NewIpfsNode(cfg *config.Config) (*IpfsNode, error) {
return nil, err return nil, err
} }
bs, err := bserv.NewBlockService(d) bs, err := bserv.NewBlockService(d, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -53,11 +53,11 @@ type IpfsDHT struct { ...@@ -53,11 +53,11 @@ type IpfsDHT struct {
} }
// NewDHT creates a new DHT object with the given peer as the 'local' host // NewDHT creates a new DHT object with the given peer as the 'local' host
func NewDHT(p *peer.Peer, net swarm.Network) *IpfsDHT { func NewDHT(p *peer.Peer, net swarm.Network, dstore ds.Datastore) *IpfsDHT {
dht := new(IpfsDHT) dht := new(IpfsDHT)
dht.network = net dht.network = net
dht.netChan = net.GetChannel(swarm.PBWrapper_DHT_MESSAGE) dht.netChan = net.GetChannel(swarm.PBWrapper_DHT_MESSAGE)
dht.datastore = ds.NewMapDatastore() dht.datastore = dstore
dht.self = p dht.self = p
dht.providers = NewProviderManager() dht.providers = NewProviderManager()
dht.shutdown = make(chan struct{}) dht.shutdown = make(chan struct{})
...@@ -322,6 +322,7 @@ type providerInfo struct { ...@@ -322,6 +322,7 @@ type providerInfo struct {
func (dht *IpfsDHT) handleAddProvider(p *peer.Peer, pmes *PBDHTMessage) { func (dht *IpfsDHT) handleAddProvider(p *peer.Peer, pmes *PBDHTMessage) {
key := u.Key(pmes.GetKey()) key := u.Key(pmes.GetKey())
u.DOut("[%s] Adding [%s] as a provider for '%s'\n", dht.self.ID.Pretty(), p.ID.Pretty(), peer.ID(key).Pretty())
dht.providers.AddProvider(key, p) dht.providers.AddProvider(key, p)
} }
...@@ -615,12 +616,8 @@ func (dht *IpfsDHT) addPeerList(key u.Key, peers []*PBDHTMessage_PBPeer) []*peer ...@@ -615,12 +616,8 @@ func (dht *IpfsDHT) addPeerList(key u.Key, peers []*PBDHTMessage_PBPeer) []*peer
p := dht.network.Find(u.Key(prov.GetId())) p := dht.network.Find(u.Key(prov.GetId()))
if p == nil { if p == nil {
u.DOut("given provider %s was not in our network already.\n", peer.ID(prov.GetId()).Pretty()) u.DOut("given provider %s was not in our network already.\n", peer.ID(prov.GetId()).Pretty())
maddr, err := ma.NewMultiaddr(prov.GetAddr()) var err error
if err != nil { p, err = dht.peerFromInfo(prov)
u.PErr("error connecting to new peer: %s\n", err)
continue
}
p, err = dht.network.GetConnection(peer.ID(prov.GetId()), maddr)
if err != nil { if err != nil {
u.PErr("error connecting to new peer: %s\n", err) u.PErr("error connecting to new peer: %s\n", err)
continue continue
...@@ -631,3 +628,12 @@ func (dht *IpfsDHT) addPeerList(key u.Key, peers []*PBDHTMessage_PBPeer) []*peer ...@@ -631,3 +628,12 @@ func (dht *IpfsDHT) addPeerList(key u.Key, peers []*PBDHTMessage_PBPeer) []*peer
} }
return provArr return provArr
} }
func (dht *IpfsDHT) peerFromInfo(pbp *PBDHTMessage_PBPeer) (*peer.Peer, error) {
maddr, err := ma.NewMultiaddr(pbp.GetAddr())
if err != nil {
return nil, err
}
return dht.network.GetConnection(peer.ID(pbp.GetId()), maddr)
}
...@@ -3,6 +3,7 @@ package dht ...@@ -3,6 +3,7 @@ package dht
import ( import (
"testing" "testing"
ds "github.com/jbenet/datastore.go"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
swarm "github.com/jbenet/go-ipfs/swarm" swarm "github.com/jbenet/go-ipfs/swarm"
u "github.com/jbenet/go-ipfs/util" u "github.com/jbenet/go-ipfs/util"
...@@ -37,7 +38,7 @@ func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT) ...@@ -37,7 +38,7 @@ func setupDHTS(n int, t *testing.T) ([]*ma.Multiaddr, []*peer.Peer, []*IpfsDHT)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
d := NewDHT(peers[i], net) d := NewDHT(peers[i], net, ds.NewMapDatastore())
dhts = append(dhts, d) dhts = append(dhts, d)
d.Start() d.Start()
} }
...@@ -69,14 +70,14 @@ func TestPing(t *testing.T) { ...@@ -69,14 +70,14 @@ func TestPing(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
dhtA := NewDHT(peerA, neta) dhtA := NewDHT(peerA, neta, ds.NewMapDatastore())
netb := swarm.NewSwarm(peerB) netb := swarm.NewSwarm(peerB)
err = netb.Listen() err = netb.Listen()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
dhtB := NewDHT(peerB, netb) dhtB := NewDHT(peerB, netb, ds.NewMapDatastore())
dhtA.Start() dhtA.Start()
dhtB.Start() dhtB.Start()
...@@ -120,14 +121,14 @@ func TestValueGetSet(t *testing.T) { ...@@ -120,14 +121,14 @@ func TestValueGetSet(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
dhtA := NewDHT(peerA, neta) dhtA := NewDHT(peerA, neta, ds.NewMapDatastore())
netb := swarm.NewSwarm(peerB) netb := swarm.NewSwarm(peerB)
err = netb.Listen() err = netb.Listen()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
dhtB := NewDHT(peerB, netb) dhtB := NewDHT(peerB, netb, ds.NewMapDatastore())
dhtA.Start() dhtA.Start()
dhtB.Start() dhtB.Start()
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"code.google.com/p/goprotobuf/proto" "code.google.com/p/goprotobuf/proto"
ds "github.com/jbenet/datastore.go"
peer "github.com/jbenet/go-ipfs/peer" peer "github.com/jbenet/go-ipfs/peer"
swarm "github.com/jbenet/go-ipfs/swarm" swarm "github.com/jbenet/go-ipfs/swarm"
u "github.com/jbenet/go-ipfs/util" u "github.com/jbenet/go-ipfs/util"
...@@ -89,7 +90,7 @@ func TestGetFailures(t *testing.T) { ...@@ -89,7 +90,7 @@ func TestGetFailures(t *testing.T) {
local := new(peer.Peer) local := new(peer.Peer)
local.ID = peer.ID("test_peer") local.ID = peer.ID("test_peer")
d := NewDHT(local, fn) d := NewDHT(local, fn, ds.NewMapDatastore())
other := &peer.Peer{ID: peer.ID("other_peer")} other := &peer.Peer{ID: peer.ID("other_peer")}
...@@ -177,7 +178,7 @@ func TestNotFound(t *testing.T) { ...@@ -177,7 +178,7 @@ func TestNotFound(t *testing.T) {
local := new(peer.Peer) local := new(peer.Peer)
local.ID = peer.ID("test_peer") local.ID = peer.ID("test_peer")
d := NewDHT(local, fn) d := NewDHT(local, fn, ds.NewMapDatastore())
d.Start() d.Start()
var ps []*peer.Peer var ps []*peer.Peer
...@@ -239,7 +240,7 @@ func TestLessThanKResponses(t *testing.T) { ...@@ -239,7 +240,7 @@ func TestLessThanKResponses(t *testing.T) {
local := new(peer.Peer) local := new(peer.Peer)
local.ID = peer.ID("test_peer") local.ID = peer.ID("test_peer")
d := NewDHT(local, fn) d := NewDHT(local, fn, ds.NewMapDatastore())
d.Start() d.Start()
var ps []*peer.Peer var ps []*peer.Peer
......
...@@ -63,7 +63,7 @@ func (dht *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) { ...@@ -63,7 +63,7 @@ func (dht *IpfsDHT) GetValue(key u.Key, timeout time.Duration) ([]byte, error) {
val, err := dht.getLocal(key) val, err := dht.getLocal(key)
if err == nil { if err == nil {
ll.Success = true ll.Success = true
u.DOut("Found local, returning.") u.DOut("Found local, returning.\n")
return val, nil return val, nil
} }
...@@ -218,6 +218,9 @@ func (dht *IpfsDHT) FindProvidersAsync(key u.Key, count int, timeout time.Durati ...@@ -218,6 +218,9 @@ func (dht *IpfsDHT) FindProvidersAsync(key u.Key, count int, timeout time.Durati
//TODO: this function could also be done asynchronously //TODO: this function could also be done asynchronously
func (dht *IpfsDHT) addPeerListAsync(k u.Key, peers []*PBDHTMessage_PBPeer, ps *peerSet, count int, out chan *peer.Peer) { func (dht *IpfsDHT) addPeerListAsync(k u.Key, peers []*PBDHTMessage_PBPeer, ps *peerSet, count int, out chan *peer.Peer) {
for _, pbp := range peers { for _, pbp := range peers {
if peer.ID(pbp.GetId()).Equal(dht.self.ID) {
continue
}
maddr, err := ma.NewMultiaddr(pbp.GetAddr()) maddr, err := ma.NewMultiaddr(pbp.GetAddr())
if err != nil { if err != nil {
u.PErr("%v\n", err) u.PErr("%v\n", err)
...@@ -256,11 +259,14 @@ func (dht *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Pee ...@@ -256,11 +259,14 @@ func (dht *IpfsDHT) FindProviders(key u.Key, timeout time.Duration) ([]*peer.Pee
return nil, err return nil, err
} }
if pmes.GetSuccess() { if pmes.GetSuccess() {
u.DOut("Got providers back from findProviders call!\n")
provs := dht.addPeerList(key, pmes.GetPeers()) provs := dht.addPeerList(key, pmes.GetPeers())
ll.Success = true ll.Success = true
return provs, nil return provs, nil
} }
u.DOut("Didnt get providers, just closer peers.\n")
closer := pmes.GetPeers() closer := pmes.GetPeers()
if len(closer) == 0 { if len(closer) == 0 {
level++ level++
...@@ -337,7 +343,7 @@ func (dht *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, err ...@@ -337,7 +343,7 @@ func (dht *IpfsDHT) FindPeer(id peer.ID, timeout time.Duration) (*peer.Peer, err
// Ping a peer, log the time it took // Ping a peer, log the time it took
func (dht *IpfsDHT) Ping(p *peer.Peer, timeout time.Duration) error { func (dht *IpfsDHT) Ping(p *peer.Peer, timeout time.Duration) error {
// Thoughts: maybe this should accept an ID and do a peer lookup? // Thoughts: maybe this should accept an ID and do a peer lookup?
u.DOut("Enter Ping.") u.DOut("Enter Ping.\n")
pmes := Message{ID: swarm.GenerateMessageID(), Type: PBDHTMessage_PING} pmes := Message{ID: swarm.GenerateMessageID(), Type: PBDHTMessage_PING}
mes := swarm.NewMessage(p, pmes.ToProtobuf()) mes := swarm.NewMessage(p, pmes.ToProtobuf())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment