Skip to content

Commit

Permalink
Merge pull request #1867 from ipfs/fix/mocknet-race
Browse files Browse the repository at this point in the history
fix a few race conditions in mocknet
  • Loading branch information
jbenet committed Oct 20, 2015
2 parents 27eece3 + def4697 commit 795e242
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 28 deletions.
56 changes: 28 additions & 28 deletions p2p/net/mock/mock_net.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type mocknet struct {

proc goprocess.Process // for Context closing
ctx context.Context
sync.RWMutex
sync.Mutex
}

func New(ctx context.Context) Mocknet {
Expand Down Expand Up @@ -95,8 +95,8 @@ func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peer.Peerstore) (host.Host
}

func (mn *mocknet) Peers() []peer.ID {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()

cp := make([]peer.ID, 0, len(mn.nets))
for _, n := range mn.nets {
Expand All @@ -107,22 +107,22 @@ func (mn *mocknet) Peers() []peer.ID {
}

func (mn *mocknet) Host(pid peer.ID) host.Host {
mn.RLock()
mn.Lock()
host := mn.hosts[pid]
mn.RUnlock()
mn.Unlock()
return host
}

func (mn *mocknet) Net(pid peer.ID) inet.Network {
mn.RLock()
mn.Lock()
n := mn.nets[pid]
mn.RUnlock()
mn.Unlock()
return n
}

func (mn *mocknet) Hosts() []host.Host {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()

cp := make([]host.Host, 0, len(mn.hosts))
for _, h := range mn.hosts {
Expand All @@ -134,8 +134,8 @@ func (mn *mocknet) Hosts() []host.Host {
}

func (mn *mocknet) Nets() []inet.Network {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()

cp := make([]inet.Network, 0, len(mn.nets))
for _, n := range mn.nets {
Expand All @@ -148,8 +148,8 @@ func (mn *mocknet) Nets() []inet.Network {
// Links returns a copy of the internal link state map.
// (wow, much map. so data structure. how compose. ahhh pointer)
func (mn *mocknet) Links() LinkMap {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()

links := map[string]map[string]map[Link]struct{}{}
for p1, lm := range mn.links {
Expand Down Expand Up @@ -179,10 +179,10 @@ func (mn *mocknet) LinkAll() error {
}

func (mn *mocknet) LinkPeers(p1, p2 peer.ID) (Link, error) {
mn.RLock()
mn.Lock()
n1 := mn.nets[p1]
n2 := mn.nets[p2]
mn.RUnlock()
mn.Unlock()

if n1 == nil {
return nil, fmt.Errorf("network for p1 not in mocknet")
Expand Down Expand Up @@ -211,11 +211,11 @@ func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
}

func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) {
mn.RLock()
mn.Lock()
n1r, err1 := mn.validate(n1)
n2r, err2 := mn.validate(n2)
ld := mn.linkDefaults
mn.RUnlock()
mn.Unlock()

if err1 != nil {
return nil, err1
Expand Down Expand Up @@ -260,7 +260,7 @@ func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
}

// get from the links map. and lazily contruct.
func (mn *mocknet) linksMapGet(p1, p2 peer.ID) *map[*link]struct{} {
func (mn *mocknet) linksMapGet(p1, p2 peer.ID) map[*link]struct{} {

l1, found := mn.links[p1]
if !found {
Expand All @@ -275,25 +275,25 @@ func (mn *mocknet) linksMapGet(p1, p2 peer.ID) *map[*link]struct{} {
l2 = l1[p2]
}

return &l2
return l2
}

func (mn *mocknet) addLink(l *link) {
mn.Lock()
defer mn.Unlock()

n1, n2 := l.nets[0], l.nets[1]
(*mn.linksMapGet(n1.peer, n2.peer))[l] = struct{}{}
(*mn.linksMapGet(n2.peer, n1.peer))[l] = struct{}{}
mn.linksMapGet(n1.peer, n2.peer)[l] = struct{}{}
mn.linksMapGet(n2.peer, n1.peer)[l] = struct{}{}
}

func (mn *mocknet) removeLink(l *link) {
mn.Lock()
defer mn.Unlock()

n1, n2 := l.nets[0], l.nets[1]
delete(*mn.linksMapGet(n1.peer, n2.peer), l)
delete(*mn.linksMapGet(n2.peer, n1.peer), l)
delete(mn.linksMapGet(n1.peer, n2.peer), l)
delete(mn.linksMapGet(n2.peer, n1.peer), l)
}

func (mn *mocknet) ConnectAllButSelf() error {
Expand Down Expand Up @@ -329,10 +329,10 @@ func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
}

func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.ID) []Link {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()

ls2 := *mn.linksMapGet(p1, p2)
ls2 := mn.linksMapGet(p1, p2)
cp := make([]Link, 0, len(ls2))
for l := range ls2 {
cp = append(cp, l)
Expand All @@ -351,8 +351,8 @@ func (mn *mocknet) SetLinkDefaults(o LinkOptions) {
}

func (mn *mocknet) LinkDefaults() LinkOptions {
mn.RLock()
defer mn.RUnlock()
mn.Lock()
defer mn.Unlock()
return mn.linkDefaults
}

Expand Down
6 changes: 6 additions & 0 deletions p2p/net/mock/ratelimiter.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package mocknet

import (
"sync"
"time"
)

// A ratelimiter is used by a link to determine how long to wait before sending
// data given a bandwidth cap.
type ratelimiter struct {
lock sync.Mutex
bandwidth float64 // bytes per nanosecond
allowance float64 // in bytes
maxAllowance float64 // in bytes
Expand All @@ -29,6 +31,8 @@ func NewRatelimiter(bandwidth float64) *ratelimiter {

// Changes bandwidth of a ratelimiter and resets its allowance
func (r *ratelimiter) UpdateBandwidth(bandwidth float64) {
r.lock.Lock()
defer r.lock.Unlock()
// Convert bandwidth from bytes/second to bytes/nanosecond
b := bandwidth / float64(time.Second)
r.bandwidth = b
Expand All @@ -40,6 +44,8 @@ func (r *ratelimiter) UpdateBandwidth(bandwidth float64) {

// Returns how long to wait before sending data with length 'dataSize' bytes
func (r *ratelimiter) Limit(dataSize int) time.Duration {
r.lock.Lock()
defer r.lock.Unlock()
// update time
var duration time.Duration = time.Duration(0)
if r.bandwidth == 0 {
Expand Down

0 comments on commit 795e242

Please sign in to comment.