This commit is contained in:
Jae Kwon
2014-07-05 23:50:06 -07:00
parent 421a9be34c
commit ec89eb168d
8 changed files with 153 additions and 126 deletions

View File

@@ -25,18 +25,18 @@ import (
type AddrBook struct {
filePath string
mtx sync.Mutex
rand *rand.Rand
key [32]byte
addrNewIndex map[string]*knownAddress // addr.String() -> knownAddress
addrNew [newBucketCount]map[string]*knownAddress
addrOld [oldBucketCount][]*knownAddress
started int32
shutdown int32
wg sync.WaitGroup
quit chan struct{}
nOld int
nNew int
mtx sync.Mutex
rand *rand.Rand
key [32]byte
addrIndex map[string]*knownAddress // new & old
addrNew [newBucketCount]map[string]*knownAddress
addrOld [oldBucketCount][]*knownAddress
started int32
shutdown int32
wg sync.WaitGroup
quit chan struct{}
nOld int
nNew int
}
const (
@@ -80,12 +80,11 @@ const (
// days since the last success before we will consider evicting an address.
minBadDays = 7
// max addresses that we will send in response to a getAddr
// (in practise the most addresses we will return from a call to AddressCache()).
getAddrMax = 2500
// max addresses that we will send in response to a GetSelection
getSelectionMax = 2500
// % of total addresses known that we will share with a call to AddressCache.
getAddrPercent = 23
// % of total addresses known that we will share with a call to GetSelection
getSelectionPercent = 23
// current version of the on-disk format.
serializationVersion = 1
@@ -104,7 +103,7 @@ func NewAddrBook(filePath string) *AddrBook {
// When modifying this, don't forget to update loadFromFile()
func (a *AddrBook) init() {
a.addrNewIndex = make(map[string]*knownAddress)
a.addrIndex = make(map[string]*knownAddress)
io.ReadFull(crand.Reader, a.key[:])
for i := range a.addrNew {
a.addrNew[i] = make(map[string]*knownAddress)
@@ -146,11 +145,15 @@ func (a *AddrBook) NeedMoreAddresses() bool {
func (a *AddrBook) Size() int {
a.mtx.Lock()
defer a.mtx.Unlock()
return a.nOld + a.nNew
return a.size()
}
// Pick a new address to connect to.
func (a *AddrBook) PickAddress(class string, newBias int) *knownAddress {
func (a *AddrBook) size() int {
return a.nNew + a.nOld
}
// Pick an address to connect to with new/old bias.
func (a *AddrBook) PickAddress(newBias int) *knownAddress {
a.mtx.Lock()
defer a.mtx.Unlock()
@@ -198,7 +201,7 @@ func (a *AddrBook) PickAddress(class string, newBias int) *knownAddress {
func (a *AddrBook) MarkGood(addr *NetAddress) {
a.mtx.Lock()
defer a.mtx.Unlock()
ka := a.addrNewIndex[addr.String()]
ka := a.addrIndex[addr.String()]
if ka == nil {
return
}
@@ -211,13 +214,47 @@ func (a *AddrBook) MarkGood(addr *NetAddress) {
func (a *AddrBook) MarkAttempt(addr *NetAddress) {
a.mtx.Lock()
defer a.mtx.Unlock()
ka := a.addrNewIndex[addr.String()]
ka := a.addrIndex[addr.String()]
if ka == nil {
return
}
ka.MarkAttempt()
}
/* Peer exchange */
// GetSelection randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
func (a *AddrBook) GetSelection() []*NetAddress {
a.mtx.Lock()
defer a.mtx.Unlock()
if a.size() == 0 {
return nil
}
allAddr := make([]*NetAddress, a.size())
i := 0
for _, v := range a.addrIndex {
allAddr[i] = v.Addr
i++
}
numAddresses := len(allAddr) * getSelectionPercent / 100
if numAddresses > getSelectionMax {
numAddresses = getSelectionMax
}
// Fisher-Yates shuffle the array. We only need to do the first
// `numAddresses' since we are throwing the rest.
for i := 0; i < numAddresses; i++ {
// pick a number between current index and the end
j := rand.Intn(len(allAddr)-i) + i
allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
}
// slice off the limit we are willing to share.
return allAddr[:numAddresses]
}
/* Loading & Saving */
type addrBookJSON struct {
@@ -290,22 +327,19 @@ func (a *AddrBook) loadFromFile(filePath string) {
for i, newBucket := range aJSON.AddrNew {
for _, ka := range newBucket {
a.addrNew[i][ka.Addr.String()] = ka
a.addrIndex[ka.Addr.String()] = ka
}
}
// Restore .addrOld
for i, oldBucket := range aJSON.AddrOld {
copy(a.addrOld[i], oldBucket)
for _, ka := range oldBucket {
a.addrIndex[ka.Addr.String()] = ka
}
}
// Restore simple fields
a.nNew = aJSON.NumNew
a.nOld = aJSON.NumOld
// Restore addrNewIndex
a.addrNewIndex = make(map[string]*knownAddress)
for _, newBucket := range a.addrNew {
for key, ka := range newBucket {
a.addrNewIndex[key] = ka
}
}
}
/* Private methods */
@@ -333,7 +367,7 @@ func (a *AddrBook) addAddress(addr, src *NetAddress) {
}
key := addr.String()
ka := a.addrNewIndex[key]
ka := a.addrIndex[key]
if ka != nil {
// Already added
@@ -351,7 +385,7 @@ func (a *AddrBook) addAddress(addr, src *NetAddress) {
}
} else {
ka = NewknownAddress(addr, src)
a.addrNewIndex[key] = ka
a.addrIndex[key] = ka
a.nNew++
}
@@ -387,7 +421,7 @@ func (a *AddrBook) expireNew(bucket int) {
v.NewRefs--
if v.NewRefs == 0 {
a.nNew--
delete(a.addrNewIndex, k)
delete(a.addrIndex, k)
}
return
}
@@ -407,7 +441,7 @@ func (a *AddrBook) expireNew(bucket int) {
oldest.NewRefs--
if oldest.NewRefs == 0 {
a.nNew--
delete(a.addrNewIndex, key)
delete(a.addrIndex, key)
}
}
}
@@ -452,12 +486,12 @@ func (a *AddrBook) moveToOld(ka *knownAddress) {
newBucket = freedBucket
}
// replace with ka in list.
// Replace with ka in list.
ka.OldBucket = Int16(oldBucket)
a.addrOld[oldBucket][rmkaIndex] = ka
rmka.OldBucket = -1
// put rmka into new bucket
// Put rmka into new bucket
rmkey := rmka.Addr.String()
log.Tracef("Replacing %s with %s in old", rmkey, addrKey)
a.addrNew[newBucket][rmkey] = rmka