github.com/avahowell/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  }