go.dedis.ch/onet/v4@v4.0.0-pre1/simul/manage/count.go (about)

     1  package manage
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"go.dedis.ch/onet/v4"
     8  	"go.dedis.ch/onet/v4/log"
     9  	"go.dedis.ch/onet/v4/network"
    10  	"golang.org/x/xerrors"
    11  )
    12  
    13  /*
    14  The count-protocol returns the number of nodes reachable in a given
    15  timeout. To correctly wait for the whole tree, every node that receives
    16  a message sends a message to the root before contacting its children.
    17  As long as the root receives those messages, he knows the counting
    18  still goes on.
    19  */
    20  
    21  func init() {
    22  	network.RegisterMessage(PrepareCount{})
    23  	network.RegisterMessage(Count{})
    24  	network.RegisterMessage(NodeIsUp{})
    25  	onet.GlobalProtocolRegister("Count", NewCount)
    26  }
    27  
    28  // ProtocolCount holds all channels. If a timeout occurs or the counting
    29  // is done, the Count-channel receives the number of nodes reachable in
    30  // the tree.
    31  type ProtocolCount struct {
    32  	*onet.TreeNodeInstance
    33  	Replies          int
    34  	Count            chan int
    35  	Quit             chan bool
    36  	timeout          time.Duration
    37  	timeoutMu        sync.Mutex
    38  	PrepareCountChan chan struct {
    39  		*onet.TreeNode
    40  		PrepareCount
    41  	}
    42  	CountChan    chan []CountMsg
    43  	NodeIsUpChan chan struct {
    44  		*onet.TreeNode
    45  		NodeIsUp
    46  	}
    47  }
    48  
    49  // PrepareCount is sent so that every node can contact the root to say
    50  // the counting is still going on.
    51  type PrepareCount struct {
    52  	Timeout time.Duration
    53  }
    54  
    55  // NodeIsUp - if it is received by the root it will reset the counter.
    56  type NodeIsUp struct{}
    57  
    58  // Count sends the number of children to the parent node.
    59  type Count struct {
    60  	Children int32
    61  }
    62  
    63  // CountMsg is wrapper around the Count-structure
    64  type CountMsg struct {
    65  	*onet.TreeNode
    66  	Count
    67  }
    68  
    69  // NewCount returns a new protocolInstance
    70  func NewCount(n *onet.TreeNodeInstance) (onet.ProtocolInstance, error) {
    71  	p := &ProtocolCount{
    72  		TreeNodeInstance: n,
    73  		Quit:             make(chan bool),
    74  		timeout:          1 * time.Second,
    75  	}
    76  	p.Count = make(chan int, 1)
    77  	t := n.Tree()
    78  	if t == nil {
    79  		return nil, xerrors.New("cannot find tree")
    80  	}
    81  	if err := p.RegisterChannelsLength(len(t.List()),
    82  		&p.CountChan, &p.PrepareCountChan, &p.NodeIsUpChan); err != nil {
    83  		log.Error("Couldn't reister channel:", err)
    84  	}
    85  	return p, nil
    86  }
    87  
    88  // Start the protocol
    89  func (p *ProtocolCount) Start() error {
    90  	// Send an empty message
    91  	log.Lvl3("Starting to count")
    92  	p.FuncPC()
    93  	return nil
    94  }
    95  
    96  // Dispatch listens for all channels and waits for a timeout in case nothing
    97  // happens for a certain duration
    98  func (p *ProtocolCount) Dispatch() error {
    99  	running := true
   100  	for running {
   101  		log.Lvl3(p.Info(), "waiting for message for", p.Timeout())
   102  		select {
   103  		case pc := <-p.PrepareCountChan:
   104  			log.Lvl3(p.Info(), "received from", pc.TreeNode.ServerIdentity.Address,
   105  				"timeout", pc.Timeout)
   106  			p.SetTimeout(pc.Timeout)
   107  			p.FuncPC()
   108  		case c := <-p.CountChan:
   109  			p.FuncC(c)
   110  			running = false
   111  		case _ = <-p.NodeIsUpChan:
   112  			if p.Parent() != nil {
   113  				err := p.SendTo(p.Parent(), &NodeIsUp{})
   114  				if err != nil {
   115  					log.Lvl2(p.Info(), "couldn't send to parent",
   116  						p.Parent().Name(), err)
   117  				}
   118  			} else {
   119  				p.Replies++
   120  			}
   121  		case <-time.After(time.Duration(p.Timeout())):
   122  			log.Lvl3(p.Info(), "timed out while waiting for", p.Timeout())
   123  			if p.IsRoot() {
   124  				log.Lvl2("Didn't get all children in time:", p.Replies)
   125  				p.Count <- p.Replies
   126  				running = false
   127  			}
   128  		}
   129  	}
   130  	p.Done()
   131  	return nil
   132  }
   133  
   134  // FuncPC handles PrepareCount messages. These messages go down the tree and
   135  // every node that receives one will reply with a 'NodeIsUp'-message
   136  func (p *ProtocolCount) FuncPC() {
   137  	if !p.IsRoot() {
   138  		err := p.SendTo(p.Parent(), &NodeIsUp{})
   139  		if err != nil {
   140  			log.Lvl2(p.Info(), "couldn't send to parent",
   141  				p.Parent().Name(), err)
   142  		}
   143  	}
   144  	if !p.IsLeaf() {
   145  		for _, child := range p.Children() {
   146  			go func(c *onet.TreeNode) {
   147  				log.Lvl3(p.Info(), "sending to", c.ServerIdentity.Address, c.ID, "timeout", p.timeout)
   148  				err := p.SendTo(c, &PrepareCount{Timeout: p.timeout})
   149  				if err != nil {
   150  					log.Lvl2(p.Info(), "couldn't send to child",
   151  						c.Name())
   152  				}
   153  			}(child)
   154  		}
   155  	} else {
   156  		p.CountChan <- nil
   157  	}
   158  }
   159  
   160  // FuncC creates a Count-message that will be received by all parents and
   161  // count the total number of children
   162  func (p *ProtocolCount) FuncC(cc []CountMsg) {
   163  	count := 1
   164  	for _, c := range cc {
   165  		count += int(c.Count.Children)
   166  	}
   167  	if !p.IsRoot() {
   168  		log.Lvl3(p.Info(), "Sends to", p.Parent().ID, p.Parent().ServerIdentity.Address)
   169  		if err := p.SendTo(p.Parent(), &Count{int32(count)}); err != nil {
   170  			log.Lvl2(p.Name(), "coouldn't send to parent",
   171  				p.Parent().Name())
   172  		}
   173  	} else {
   174  		p.Count <- count
   175  	}
   176  	log.Lvl3(p.ServerIdentity().Address, "Done")
   177  }
   178  
   179  // SetTimeout sets the new timeout
   180  func (p *ProtocolCount) SetTimeout(t time.Duration) {
   181  	p.timeoutMu.Lock()
   182  	p.timeout = t
   183  	p.timeoutMu.Unlock()
   184  }
   185  
   186  // Timeout returns the current timeout
   187  func (p *ProtocolCount) Timeout() time.Duration {
   188  	p.timeoutMu.Lock()
   189  	defer p.timeoutMu.Unlock()
   190  	return p.timeout
   191  }