github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/exchange/bitswap/bitswap.go (about) 1 // package bitswap implements the IPFS Exchange interface with the BitSwap 2 // bilateral exchange protocol. 3 package bitswap 4 5 import ( 6 "time" 7 8 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" 9 ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" 10 11 blocks "github.com/jbenet/go-ipfs/blocks" 12 blockstore "github.com/jbenet/go-ipfs/blockstore" 13 exchange "github.com/jbenet/go-ipfs/exchange" 14 bsmsg "github.com/jbenet/go-ipfs/exchange/bitswap/message" 15 bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network" 16 notifications "github.com/jbenet/go-ipfs/exchange/bitswap/notifications" 17 strategy "github.com/jbenet/go-ipfs/exchange/bitswap/strategy" 18 inet "github.com/jbenet/go-ipfs/net" 19 peer "github.com/jbenet/go-ipfs/peer" 20 u "github.com/jbenet/go-ipfs/util" 21 ) 22 23 var log = u.Logger("bitswap") 24 25 // NetMessageSession initializes a BitSwap session that communicates over the 26 // provided NetMessage service. 27 // Runs until context is cancelled 28 func NetMessageSession(ctx context.Context, p peer.Peer, 29 net inet.Network, srv inet.Service, directory bsnet.Routing, 30 d ds.ThreadSafeDatastore, nice bool) exchange.Interface { 31 32 networkAdapter := bsnet.NetMessageAdapter(srv, net, nil) 33 34 notif := notifications.New() 35 36 go func() { 37 select { 38 case <-ctx.Done(): 39 notif.Shutdown() 40 } 41 }() 42 43 bs := &bitswap{ 44 blockstore: blockstore.NewBlockstore(d), 45 notifications: notif, 46 strategy: strategy.New(nice), 47 routing: directory, 48 sender: networkAdapter, 49 wantlist: u.NewKeySet(), 50 } 51 networkAdapter.SetDelegate(bs) 52 53 return bs 54 } 55 56 // bitswap instances implement the bitswap protocol. 57 type bitswap struct { 58 59 // sender delivers messages on behalf of the session 60 sender bsnet.Adapter 61 62 // blockstore is the local database 63 // NB: ensure threadsafety 64 blockstore blockstore.Blockstore 65 66 // routing interface for communication 67 routing bsnet.Routing 68 69 notifications notifications.PubSub 70 71 // strategy listens to network traffic and makes decisions about how to 72 // interact with partners. 73 // TODO(brian): save the strategy's state to the datastore 74 strategy strategy.Strategy 75 76 wantlist u.KeySet 77 } 78 79 // GetBlock attempts to retrieve a particular block from peers within the 80 // deadline enforced by the context 81 // 82 // TODO ensure only one active request per key 83 func (bs *bitswap) Block(parent context.Context, k u.Key) (*blocks.Block, error) { 84 log.Debugf("Get Block %v", k) 85 now := time.Now() 86 defer func() { 87 log.Debugf("GetBlock took %f secs", time.Now().Sub(now).Seconds()) 88 }() 89 90 ctx, cancelFunc := context.WithCancel(parent) 91 defer cancelFunc() 92 93 bs.wantlist.Add(k) 94 promise := bs.notifications.Subscribe(ctx, k) 95 96 const maxProviders = 20 97 peersToQuery := bs.routing.FindProvidersAsync(ctx, k, maxProviders) 98 99 go func() { 100 message := bsmsg.New() 101 for _, wanted := range bs.wantlist.Keys() { 102 message.AddWanted(wanted) 103 } 104 for peerToQuery := range peersToQuery { 105 log.Debugf("bitswap got peersToQuery: %s", peerToQuery) 106 go func(p peer.Peer) { 107 108 log.Debugf("bitswap dialing peer: %s", p) 109 err := bs.sender.DialPeer(ctx, p) 110 if err != nil { 111 log.Errorf("Error sender.DialPeer(%s)", p) 112 return 113 } 114 115 response, err := bs.sender.SendRequest(ctx, p, message) 116 if err != nil { 117 log.Error("Error sender.SendRequest(%s) = %s", p, err) 118 return 119 } 120 // FIXME ensure accounting is handled correctly when 121 // communication fails. May require slightly different API to 122 // get better guarantees. May need shared sequence numbers. 123 bs.strategy.MessageSent(p, message) 124 125 if response == nil { 126 return 127 } 128 bs.ReceiveMessage(ctx, p, response) 129 }(peerToQuery) 130 } 131 }() 132 133 select { 134 case block := <-promise: 135 bs.wantlist.Remove(k) 136 return &block, nil 137 case <-parent.Done(): 138 return nil, parent.Err() 139 } 140 } 141 142 // HasBlock announces the existance of a block to this bitswap service. The 143 // service will potentially notify its peers. 144 func (bs *bitswap) HasBlock(ctx context.Context, blk blocks.Block) error { 145 log.Debugf("Has Block %v", blk.Key()) 146 bs.wantlist.Remove(blk.Key()) 147 bs.sendToPeersThatWant(ctx, blk) 148 return bs.routing.Provide(ctx, blk.Key()) 149 } 150 151 // TODO(brian): handle errors 152 func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) ( 153 peer.Peer, bsmsg.BitSwapMessage) { 154 log.Debugf("ReceiveMessage from %v", p.Key()) 155 log.Debugf("Message wantlist: %v", incoming.Wantlist()) 156 157 if p == nil { 158 log.Error("Received message from nil peer!") 159 // TODO propagate the error upward 160 return nil, nil 161 } 162 if incoming == nil { 163 log.Error("Got nil bitswap message!") 164 // TODO propagate the error upward 165 return nil, nil 166 } 167 168 // Record message bytes in ledger 169 // TODO: this is bad, and could be easily abused. 170 // Should only track *useful* messages in ledger 171 bs.strategy.MessageReceived(p, incoming) // FIRST 172 173 for _, block := range incoming.Blocks() { 174 // TODO verify blocks? 175 if err := bs.blockstore.Put(&block); err != nil { 176 continue // FIXME(brian): err ignored 177 } 178 bs.notifications.Publish(block) 179 err := bs.HasBlock(ctx, block) 180 if err != nil { 181 log.Warningf("HasBlock errored: %s", err) 182 } 183 } 184 185 message := bsmsg.New() 186 for _, wanted := range bs.wantlist.Keys() { 187 message.AddWanted(wanted) 188 } 189 for _, key := range incoming.Wantlist() { 190 // TODO: might be better to check if we have the block before checking 191 // if we should send it to someone 192 if bs.strategy.ShouldSendBlockToPeer(key, p) { 193 if block, errBlockNotFound := bs.blockstore.Get(key); errBlockNotFound != nil { 194 continue 195 } else { 196 message.AddBlock(*block) 197 } 198 } 199 } 200 defer bs.strategy.MessageSent(p, message) 201 202 log.Debug("Returning message.") 203 return p, message 204 } 205 206 func (bs *bitswap) ReceiveError(err error) { 207 log.Errorf("Bitswap ReceiveError: %s", err) 208 // TODO log the network error 209 // TODO bubble the network error up to the parent context/error logger 210 } 211 212 // send strives to ensure that accounting is always performed when a message is 213 // sent 214 func (bs *bitswap) send(ctx context.Context, p peer.Peer, m bsmsg.BitSwapMessage) { 215 bs.sender.SendMessage(ctx, p, m) 216 bs.strategy.MessageSent(p, m) 217 } 218 219 func (bs *bitswap) sendToPeersThatWant(ctx context.Context, block blocks.Block) { 220 log.Debugf("Sending %v to peers that want it", block.Key()) 221 222 for _, p := range bs.strategy.Peers() { 223 if bs.strategy.BlockIsWantedByPeer(block.Key(), p) { 224 log.Debugf("%v wants %v", p, block.Key()) 225 if bs.strategy.ShouldSendBlockToPeer(block.Key(), p) { 226 message := bsmsg.New() 227 message.AddBlock(block) 228 for _, wanted := range bs.wantlist.Keys() { 229 message.AddWanted(wanted) 230 } 231 bs.send(ctx, p, message) 232 } 233 } 234 } 235 }