github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/renter/pool.go (about) 1 package renter 2 3 import ( 4 "github.com/NebulousLabs/Sia/modules" 5 "github.com/NebulousLabs/Sia/modules/renter/contractor" 6 ) 7 8 // A hostPool is a collection of active host connections, in the form of 9 // Editors. The renter uses a hostPool to prevent connecting to the same host 10 // more than once. This is more efficient, and also makes it easier to 11 // serialize contract revisions. 12 type hostPool struct { 13 hosts []contractor.Editor 14 blacklist []modules.NetAddress 15 hostContractor hostContractor 16 hdb hostDB 17 } 18 19 // Close closes all of the hostPool's open host connections. 20 func (p *hostPool) Close() error { 21 for _, h := range p.hosts { 22 h.Close() 23 } 24 return nil 25 } 26 27 // add adds a contract's host to the hostPool and returns it as an Editor. 28 func (p *hostPool) add(contract modules.RenterContract) (contractor.Editor, error) { 29 for _, h := range p.hosts { 30 if h.Address() == contract.NetAddress { 31 return h, nil 32 } 33 } 34 hu, err := p.hostContractor.Editor(contract) 35 if err != nil { 36 p.blacklist = append(p.blacklist, contract.NetAddress) 37 return nil, err 38 } 39 p.hosts = append(p.hosts, hu) 40 return hu, nil 41 } 42 43 // remove disconnects from a host and adds it to the blacklist. 44 func (p *hostPool) remove(addr modules.NetAddress) { 45 for i, h := range p.hosts { 46 if h.Address() == addr { 47 h.Close() 48 p.hosts = append(p.hosts[:i], p.hosts[i+1:]...) 49 p.blacklist = append(p.blacklist, addr) 50 return 51 } 52 } 53 } 54 55 // uniqueHosts will return up to 'n' unique hosts that are not in 'exclude'. 56 // The pool draws from its set of active connections first, and then negotiates 57 // new contracts if more hosts are required. Note that this latter case 58 // requires network I/O, so the caller should always assume that uniqueHosts 59 // will block. 60 func (p *hostPool) uniqueHosts(n int, exclude []modules.NetAddress) (hosts []contractor.Editor) { 61 if n == 0 { 62 return 63 } 64 65 // convert slice to map for easier lookups 66 excludeSet := make(map[modules.NetAddress]struct{}) 67 for _, ip := range exclude { 68 excludeSet[ip] = struct{}{} 69 } 70 71 // First reuse existing connections. 72 for _, h := range p.hosts { 73 if _, ok := excludeSet[h.Address()]; ok { 74 continue 75 } 76 hosts = append(hosts, h) 77 if len(hosts) >= n { 78 return hosts 79 } 80 } 81 82 // Extend the exclude set with the pool's blacklist, and the hosts we're 83 // already connected to. 84 for _, ip := range p.blacklist { 85 excludeSet[ip] = struct{}{} 86 } 87 for _, h := range p.hosts { 88 excludeSet[h.Address()] = struct{}{} 89 } 90 91 // Next try to reuse existing contracts. 92 for _, contract := range p.hostContractor.Contracts() { 93 if _, ok := excludeSet[contract.NetAddress]; ok { 94 continue 95 } 96 hu, err := p.add(contract) 97 if err != nil { 98 continue 99 } 100 hosts = append(hosts, hu) 101 excludeSet[hu.Address()] = struct{}{} 102 if len(hosts) >= n { 103 break 104 } 105 } 106 107 return hosts 108 } 109 110 // newHostPool returns an empty hostPool. 111 func (r *Renter) newHostPool() *hostPool { 112 return &hostPool{ 113 hostContractor: r.hostContractor, 114 hdb: r.hostDB, 115 } 116 }