func (self *ExchangeProtocol) PropagatePeer(peer string, addr string, ignoreset *IgnoreSet, request *pb.LearnReportRequest) (bool, error, time.Duration) {
	if peer == self.Id {
		du.LogD(etag, "skip propagating to self")
		return true, nil, 0  
	}
	report := request.Report
	if ignoreset != nil {
		if ignoreset.Test(peer) {
			du.LogI(etag, "skip propagating report about %s to %s", report.Subject, peer)
			return true, nil, 0
		}
	}
	du.LogD(etag, "propagating report about %s to %s", report.Subject, peer)
	client, err := self.getOrMakeClient(peer)
	if err != nil {
		du.LogE(etag, "failed to get client for %s", peer)
		return false, err, 0
	}
	t1 := time.Now()
	reply, err := client.LearnReport(context.Background(), request)
	duration := time.Since(t1)
	if err != nil {
		du.LogE(etag, "failed to propagate report about %s to %s", report.Subject, peer)
		return false, err, duration
	}
	if request.Kind == pb.LearnReportRequest_NORMAL && reply.Result == pb.LearnReportReply_IGNORED {
		if ignoreset == nil {
			ignoreset = NewIgnoreSet()
			self.mu.Lock()
			self.SkipSubjectPeers[report.Subject] = ignoreset
			self.mu.Unlock()
		}
		ignoreset.Set(peer)
		du.LogI(etag, "stop propgating report on subject %s to %s in the future", report.Subject, peer)
		return true, nil, duration
	} else {
		du.LogI(etag, "propagated report about %s to %s at %s in %s", report.Subject, peer, addr, duration)
		return false, nil, duration
	}
}
Propagate something to a peer. This something could be a normal report or a
subscription/unsubscription request. In the former case, we should check
if the receiver peer is interested in knowing the report. If not, we
should stop propagating the report to the receiver in the future until
it becomes interested in the report again.
package exchange
import (
	"sync"
	"time"
	"github.com/golang/protobuf/ptypes"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	pb "panorama/build/gen"
	dt "panorama/types"
	du "panorama/util"
)
const (
	etag = "exchange"
)
type IgnoreSet struct {
	mu      sync.RWMutex
	entries map[string]bool
}
type ExchangeProtocol struct {
	Id   string  
	Addr string  
	Peers            map[string]string      
	SkipSubjectPeers map[string]*IgnoreSet  
	Clients map[string]pb.HealthServiceClient  
	me *pb.Peer
	mu sync.RWMutex
}
var _ dt.HealthExchange = new(ExchangeProtocol)
func NewIgnoreSet() *IgnoreSet {
	return &IgnoreSet{
		entries: make(map[string]bool),
	}
}
func NewExchangeProtocol(config *dt.HealthServerConfig) *ExchangeProtocol {
	return &ExchangeProtocol{
		Id:               config.Id,
		Addr:             config.Addr,
		Peers:            config.Peers,
		SkipSubjectPeers: make(map[string]*IgnoreSet),
		Clients:          make(map[string]pb.HealthServiceClient),
		me:               &pb.Peer{Id: string(config.Id), Addr: config.Addr},
	}
}
func (self *IgnoreSet) Test(peer string) bool {
	self.mu.RLock()
	_, ok := self.entries[peer]
	self.mu.RUnlock()
	return ok
}
func (self *IgnoreSet) Set(peer string) {
	self.mu.Lock()
	self.entries[peer] = true
	self.mu.Unlock()
}
func (self *IgnoreSet) Remove(subject string, peer string) {
	self.mu.Lock()
	_, ok := self.entries[peer]
	delete(self.entries, peer)  
	if ok {
		du.LogD(etag, "removing %s from the ignoreset of peer %s", subject, peer)
	}
	self.mu.Unlock()
}
func (self *ExchangeProtocol) Subscribe(subject string) error {
	report := &pb.Report{Observer: self.me.Id, Subject: subject}
	request := &pb.LearnReportRequest{Kind: pb.LearnReportRequest_SUBSCRIPTION, Source: self.me, Report: report}
	du.LogI(etag, "subscribe to reports about for %s", report.Subject)
	return self.PropagateAll(request)
}
func (self *ExchangeProtocol) Unsubscribe(subject string) error {
	report := &pb.Report{Observer: self.me.Id, Subject: subject}
	request := &pb.LearnReportRequest{Kind: pb.LearnReportRequest_UNSUBSCRIPTION, Source: self.me, Report: report}
	du.LogI(etag, "unsubscribe to reports about for %s", report.Subject)
	return self.PropagateAll(request)
}
func (self *ExchangeProtocol) Propagate(report *pb.Report) error {
	request := &pb.LearnReportRequest{Kind: pb.LearnReportRequest_NORMAL, Source: self.me, Report: report}
	du.LogI(etag, "about to propagate report about %s", report.Subject)
	return self.PropagateAll(request)
}