github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/peer/queue/sync.go (about) 1 package queue 2 3 import ( 4 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 5 peer "github.com/ipfs/go-ipfs/p2p/peer" 6 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 7 ) 8 9 var log = eventlog.Logger("peerqueue") 10 11 // ChanQueue makes any PeerQueue synchronizable through channels. 12 type ChanQueue struct { 13 Queue PeerQueue 14 EnqChan chan<- peer.ID 15 DeqChan <-chan peer.ID 16 } 17 18 // NewChanQueue creates a ChanQueue by wrapping pq. 19 func NewChanQueue(ctx context.Context, pq PeerQueue) *ChanQueue { 20 cq := &ChanQueue{Queue: pq} 21 cq.process(ctx) 22 return cq 23 } 24 25 func (cq *ChanQueue) process(ctx context.Context) { 26 // construct the channels here to be able to use them bidirectionally 27 enqChan := make(chan peer.ID) 28 deqChan := make(chan peer.ID) 29 30 cq.EnqChan = enqChan 31 cq.DeqChan = deqChan 32 33 go func() { 34 log.Debug("processing") 35 defer log.Debug("closed") 36 defer close(deqChan) 37 38 var next peer.ID 39 var item peer.ID 40 var more bool 41 42 for { 43 if cq.Queue.Len() == 0 { 44 // log.Debug("wait for enqueue") 45 select { 46 case next, more = <-enqChan: 47 if !more { 48 return 49 } 50 // log.Debug("got", next) 51 52 case <-ctx.Done(): 53 return 54 } 55 56 } else { 57 next = cq.Queue.Dequeue() 58 // log.Debug("peek", next) 59 } 60 61 select { 62 case item, more = <-enqChan: 63 if !more { 64 if cq.Queue.Len() > 0 { 65 return // we're done done. 66 } 67 enqChan = nil // closed, so no use. 68 } 69 // log.Debug("got", item) 70 cq.Queue.Enqueue(item) 71 cq.Queue.Enqueue(next) // order may have changed. 72 next = "" 73 74 case deqChan <- next: 75 // log.Debug("dequeued", next) 76 next = "" 77 78 case <-ctx.Done(): 79 return 80 } 81 } 82 83 }() 84 }