|
|
@ -4,7 +4,6 @@ import ( |
|
|
|
"container/heap" |
|
|
|
"fmt" |
|
|
|
"math/rand" |
|
|
|
"strings" |
|
|
|
) |
|
|
|
|
|
|
|
const seed = 0 |
|
|
@ -91,12 +90,7 @@ func (p *Peer) setWants(part uint16, want bool) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Did we give peer a part
|
|
|
|
func (p *Peer) gave(part uint16) bool { |
|
|
|
return p.given[part/8]&(1<<(part%8)) > 0 |
|
|
|
} |
|
|
|
|
|
|
|
func (p *Peer) setGave(part uint16) { |
|
|
|
func (p *Peer) setGiven(part uint16) { |
|
|
|
p.given[part/8] |= (1 << (part % 8)) |
|
|
|
} |
|
|
|
|
|
|
@ -187,46 +181,6 @@ func (n *Node) isFull() bool { |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
func (n *Node) pickRandomForPeer(peer *Peer) (part uint16, ok bool) { |
|
|
|
// Pick a random piece that node has and give it to peer.
|
|
|
|
// Do not pick a piece that has already been given.
|
|
|
|
peerGiven := peer.given |
|
|
|
nodeParts := n.parts |
|
|
|
randStart := rand.Intn(numNodes8) |
|
|
|
for i := 0; i < numNodes8; i++ { |
|
|
|
bytei := uint16((i + randStart) % numNodes8) |
|
|
|
pByte := peerGiven[bytei] |
|
|
|
nByte := nodeParts[bytei] |
|
|
|
iHas := nByte & ^pByte // iHas something to give :)
|
|
|
|
if iHas > 0 { |
|
|
|
randBitStart := rand.Intn(8) |
|
|
|
//fmt.Println("//--")
|
|
|
|
for j := 0; j < 8; j++ { |
|
|
|
biti := uint16((j + randBitStart) % 8) |
|
|
|
//fmt.Printf("%X %v %v %v\n", iHas, j, biti, randBitStart)
|
|
|
|
if (iHas & (1 << biti)) > 0 { |
|
|
|
return 8*bytei + biti, true |
|
|
|
} |
|
|
|
} |
|
|
|
panic("should not happen") |
|
|
|
} |
|
|
|
} |
|
|
|
return 0, false |
|
|
|
} |
|
|
|
|
|
|
|
func (n *Node) debug() { |
|
|
|
lines := []string{} |
|
|
|
lines = append(lines, n.String()) |
|
|
|
lines = append(lines, fmt.Sprintf("events: %v, parts: %X", n.events.Len(), n.parts)) |
|
|
|
for _, p := range n.peers { |
|
|
|
part, ok := n.pickRandomForPeer(p) |
|
|
|
lines = append(lines, fmt.Sprintf("peer sent: %v, given: %X, (%v/%v)", p.sent, p.given, part, ok)) |
|
|
|
} |
|
|
|
fmt.Println("//---------------") |
|
|
|
fmt.Println(strings.Join(lines, "\n")) |
|
|
|
fmt.Println("//---------------") |
|
|
|
} |
|
|
|
|
|
|
|
func (n *Node) String() string { |
|
|
|
return fmt.Sprintf("{N:%d}", n.index) |
|
|
|
} |
|
|
@ -332,11 +286,12 @@ func countFull(nodes []*Node) (fullCount int) { |
|
|
|
type runStat struct { |
|
|
|
time int32 // time for all events to propagate
|
|
|
|
fill float64 // avg % of pieces gotten
|
|
|
|
full float64 // % of times the sendQueue was full
|
|
|
|
dups float64 // % of times that a received data was duplicate
|
|
|
|
succ float64 // % of times the sendQueue was not full
|
|
|
|
} |
|
|
|
|
|
|
|
func (s runStat) String() string { |
|
|
|
return fmt.Sprintf("{t:%v/fi:%.5f/fu:%.5f}", s.time, s.fill, s.full) |
|
|
|
return fmt.Sprintf("{t:%v/fi:%.5f/su:%.5f/du:%.5f}", s.time, s.fill, s.succ, s.dups) |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
@ -375,6 +330,8 @@ func main() { |
|
|
|
numEventsZero := 0 // times no events have occured
|
|
|
|
numSendSuccess := 0 // times data send was successful
|
|
|
|
numSendFailure := 0 // times data send failed due to queue being full
|
|
|
|
numReceives := 0 // number of data items received
|
|
|
|
numDups := 0 // number of data items that were duplicate
|
|
|
|
|
|
|
|
// Run simulation
|
|
|
|
for { |
|
|
@ -408,27 +365,32 @@ func main() { |
|
|
|
switch _event.(type) { |
|
|
|
case EventData: |
|
|
|
event := _event.(EventData) |
|
|
|
numEvents++ |
|
|
|
|
|
|
|
// Process this event
|
|
|
|
rank := node.receive(event.part) |
|
|
|
// Send rank back to peer
|
|
|
|
// NOTE: in reality, maybe this doesn't always happen.
|
|
|
|
srcPeer := node.peers[event.src] |
|
|
|
srcPeer.setGave(event.part) // HACK
|
|
|
|
srcPeer.setGiven(event.part) // HACK
|
|
|
|
srcPeer.sendEventDataResponse(EventDataResponse{ |
|
|
|
time: event.time + latencyMS, // TODO: responseTxMS ?
|
|
|
|
src: srcPeer.remote, |
|
|
|
part: event.part, |
|
|
|
rank: rank, |
|
|
|
}) |
|
|
|
numEvents++ |
|
|
|
|
|
|
|
if rank > 1 { |
|
|
|
// Already has this part, ignore this event.
|
|
|
|
numReceives++ |
|
|
|
numDups++ |
|
|
|
continue |
|
|
|
} else { |
|
|
|
numReceives++ |
|
|
|
} |
|
|
|
|
|
|
|
// Let's iterate over peers & see which wants this piece.
|
|
|
|
// We don't need to check peer.given because duplicate parts are ignored.
|
|
|
|
for _, peer := range node.peers { |
|
|
|
if peer.wants(event.part) { |
|
|
|
//fmt.Print("w")
|
|
|
@ -438,7 +400,7 @@ func main() { |
|
|
|
part: event.part, |
|
|
|
}) |
|
|
|
if sent { |
|
|
|
peer.setGave(event.part) |
|
|
|
peer.setGiven(event.part) |
|
|
|
numSendSuccess++ |
|
|
|
} else { |
|
|
|
numSendFailure++ |
|
|
@ -446,18 +408,17 @@ func main() { |
|
|
|
} else { |
|
|
|
//fmt.Print("!")
|
|
|
|
// Peer doesn't want it, but sporadically we'll try sending it anyways.
|
|
|
|
if peer.canSendData(event.time) && |
|
|
|
rand.Float32() < tryUnsolicited { |
|
|
|
if rand.Float32() < tryUnsolicited { |
|
|
|
sent := peer.sendEventData(EventData{ |
|
|
|
time: event.time + latencyMS + partTxMS, |
|
|
|
src: peer.remote, |
|
|
|
part: event.part, |
|
|
|
}) |
|
|
|
if sent { |
|
|
|
peer.setGave(event.part) |
|
|
|
numSendSuccess++ |
|
|
|
peer.setGiven(event.part) |
|
|
|
// numSendSuccess++
|
|
|
|
} else { |
|
|
|
numSendFailure++ |
|
|
|
// numSendFailure++
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -490,11 +451,15 @@ func main() { |
|
|
|
for _, node := range nodes { |
|
|
|
fillSum += node.fill() |
|
|
|
} |
|
|
|
runStats = append(runStats, runStat{timeMS, fillSum / float64(numNodes), float64(numSendSuccess) / float64(numSendSuccess+numSendFailure)}) |
|
|
|
runStats = append(runStats, runStat{timeMS, fillSum / float64(numNodes), float64(numSendSuccess) / float64(numSendSuccess+numSendFailure), float64(numDups) / float64(numReceives)}) |
|
|
|
for i := 0; i < 20; i++ { |
|
|
|
node := nodes[i] |
|
|
|
fmt.Printf("[%v] parts: %X (%f)\n", node.index, node.parts[:80], node.fill()) |
|
|
|
} |
|
|
|
for i := 20; i < 2000; i += 200 { |
|
|
|
node := nodes[i] |
|
|
|
fmt.Printf("[%v] parts: %X (%f)\n", node.index, node.parts[:80], node.fill()) |
|
|
|
} |
|
|
|
break |
|
|
|
} else { |
|
|
|
fmt.Printf("simulated %v ms. numEvents: %v Past: %v\n", timeMS, numEvents, runStats) |
|
|
@ -512,15 +477,6 @@ func main() { |
|
|
|
// Lets increment the timeMS now
|
|
|
|
timeMS += latencyMS / 2 |
|
|
|
|
|
|
|
/* |
|
|
|
// Debug
|
|
|
|
if timeMS >= 25000 { |
|
|
|
nodes[1].debug() |
|
|
|
for e := nodes[1].events.Pop(); e != nil; e = nodes[1].events.Pop() { |
|
|
|
fmt.Println(e) |
|
|
|
} |
|
|
|
return |
|
|
|
} */ |
|
|
|
} // end simulation
|
|
|
|
} // forever loop
|
|
|
|
} |
|
|
|