routing.go 1.82 KB
Newer Older
Brian Tiger Chow's avatar
Brian Tiger Chow committed
1 2 3
package bitswap

import (
4
	"math/rand"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5 6 7
	"sync"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8
	bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
9 10 11 12 13 14 15 16 17 18
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

type RoutingServer interface {
	Announce(*peer.Peer, u.Key) error

	Providers(u.Key) []*peer.Peer

	// Returns a Routing instance configured to query this hash table
19
	Client(*peer.Peer) bsnet.Routing
Brian Tiger Chow's avatar
Brian Tiger Chow committed
20 21
}

22
func VirtualRoutingServer() RoutingServer {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
23
	return &hashTable{
24
		providers: make(map[u.Key]peer.Map),
Brian Tiger Chow's avatar
Brian Tiger Chow committed
25 26 27 28
	}
}

type hashTable struct {
29 30
	lock      sync.RWMutex
	providers map[u.Key]peer.Map
Brian Tiger Chow's avatar
Brian Tiger Chow committed
31 32 33 34 35 36
}

func (rs *hashTable) Announce(p *peer.Peer, k u.Key) error {
	rs.lock.Lock()
	defer rs.lock.Unlock()

37
	_, ok := rs.providers[k]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
38
	if !ok {
39
		rs.providers[k] = make(peer.Map)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
40
	}
41
	rs.providers[k][p.Key()] = p
Brian Tiger Chow's avatar
Brian Tiger Chow committed
42 43 44 45 46 47 48
	return nil
}

func (rs *hashTable) Providers(k u.Key) []*peer.Peer {
	rs.lock.RLock()
	defer rs.lock.RUnlock()
	ret := make([]*peer.Peer, 0)
49
	peerset, ok := rs.providers[k]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
50 51 52
	if !ok {
		return ret
	}
53
	for _, peer := range peerset {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
54 55
		ret = append(ret, peer)
	}
56 57 58 59 60 61

	for i := range ret {
		j := rand.Intn(i + 1)
		ret[i], ret[j] = ret[j], ret[i]
	}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
62 63 64
	return ret
}

65
func (rs *hashTable) Client(p *peer.Peer) bsnet.Routing {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
	return &routingClient{
		peer:      p,
		hashTable: rs,
	}
}

type routingClient struct {
	peer      *peer.Peer
	hashTable RoutingServer
}

func (a *routingClient) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan *peer.Peer {
	out := make(chan *peer.Peer)
	go func() {
		defer close(out)
		for i, p := range a.hashTable.Providers(k) {
			if max <= i {
				return
			}
			select {
			case out <- p:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

func (a *routingClient) Provide(key u.Key) error {
	return a.hashTable.Announce(a.peer, key)
}