github.com/DARA-Project/GoDist-Scheduler@v0.0.0-20201030134746-668de4acea0d/examples/broadcastUDPHashThread_test/broadcastUDPHashThread.go (about)

     1  
     2  package main
     3  
     4  /* This example program tests Dara's ability to reliably replay a
     5  * system with mulitple nodes communicating via UDP. The number of
     6  * nodes in the system is set by the enviornment variable
     7  * DARATESETPEERS. After beginning each peer resolves the UDP addresses
     8  * and saves an MD5 Hash of its ID. This program is an exstention of
     9  * the other broadcast protocol in that it has multiple threads running
    10  * three seperate tasks. The tasks are 1) reading from the network 2)
    11  * computing the hash, 3) broadcasting hashes. Each task has
    12  * THREADSPERJOB instances, each of which communicates with eachother
    13  * over shared channels in a pipelined fashion picutred below
    14  
    15  where THREADSPERJOB = 3
    16  
    17  readhashmsg(0)-\          /> calculatehash(0)-\           /> broadcast(0)
    18  readhashmsg(1)--> recchan -> calculatehash(1)--> writechan-> broadcast(1)
    19  readhashmsg(2)-/          \> calculatehash(2)-/           \> broadcast(2)
    20  
    21  
    22  The algorithm for this program is thus.
    23  
    24  1) Each node broadcasts its current MD5 hash starting at a RANDOM peer address
    25  2) Each node waits to recieve a single hash
    26  3) Upon recipt a nodes current hash = M55( hash + receivedHash)
    27  4) Print the current hash + size
    28  
    29  This algorithm has the advantage that any nondeterminism in the nodes
    30  will cause the hashes that they compute to differ immidiatly, thereby
    31  making the ouput of the program sensitive to every nondeterminisic
    32  action.
    33  
    34  This program is nondermanistic in the following ways
    35  
    36  1) The order in which messages are placed on the network by any node.
    37  2) The order in which messagesa are received from the network by all nodes.
    38  3) The order in which each node sends it's messages
    39  4) The order in which nodes process their messages. This refers to the 
    40  	global order of all events.
    41  5) The threadID of each processing node in the pipeline
    42  
    43  */
    44  
    45  import (
    46  	"fmt"
    47  	"os"
    48  	"net"
    49  	"log"
    50  	"strconv"
    51  	"crypto/md5"
    52  	"time"
    53  	"math/rand"
    54  )
    55  
    56  const (
    57  	BROADCASTS = 50
    58  	BUFSIZE = md5.Size
    59  	THREADSPERJOB = 3
    60  )
    61  
    62  var (
    63  	logger *log.Logger
    64  	DaraPID int
    65  	DaraTestPeers int
    66  	conn *net.UDPConn
    67  	hash string
    68  	r *rand.Rand
    69  	recchan chan string
    70  	writechan chan string
    71  	done chan bool
    72  )
    73  
    74  func main() {
    75  	logger = log.New(os.Stdout, "[INITALIZING]",log.Lshortfile)
    76  	ParseEnviornment()
    77  	SetupUDPNetworkConnections()
    78  	defer conn.Close()
    79  	logger.SetPrefix(fmt.Sprintf("[Peer %d] ",DaraPID))
    80  	logger.Printf("DaraPID: %d\tDaraTestPeers:%d\n",DaraPID,DaraTestPeers)
    81  
    82  	recchan = make(chan string, THREADSPERJOB)
    83  	writechan = make(chan string, THREADSPERJOB)
    84  	done = make(chan bool,1)
    85  
    86  	rand.Seed(int64(time.Now().Nanosecond()))
    87  	r = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
    88  
    89  	hashf := md5.New()
    90  	hash = string(hashf.Sum([]byte(fmt.Sprintf("%d",DaraPID))))
    91  	logger.Printf("Hash:%x\n",hash)
    92  	
    93  	time.Sleep(time.Second)
    94  
    95  	//Startup Threads
    96  	for i:= 0;i<THREADSPERJOB;i++ {
    97  		logger.Printf("Starting job set %d\n",i)
    98  		go readhashmsg(i)
    99  		go calculateHash(i)
   100  		go broadcast(i)
   101  	}
   102  
   103  	writechan <- hash
   104  	<-done
   105  	logger.Printf("EXIT")
   106  
   107  
   108  
   109  }
   110  
   111  func calculateHash(tid int) {
   112  	logger.Printf("Calculating Hashes on %d",tid)
   113  	hashf := md5.New()
   114  	for {
   115  		rechash := <- recchan
   116  		hash = string(hashf.Sum([]byte(hash+rechash)))
   117  		writechan <- hash
   118  	}
   119  }
   120  
   121  
   122  func broadcast(tid int) {
   123  	logger.Printf("Broadcasting Hashes on %d",tid)
   124  	for bcasts:=0;bcasts<BROADCASTS;bcasts++{
   125  		h := <- writechan
   126  		peerstart := (r.Int() % (DaraTestPeers+1))
   127  		if peerstart == 0 {
   128  			peerstart = 1
   129  		}
   130  		var counter = 1
   131  		for i:=peerstart;counter<=DaraTestPeers;counter++{
   132  			logger.Printf("BROADCASTING %d Peerstart %d Tid %d Hash% s\n",i,peerstart,tid,h)
   133  			if i == DaraPID {
   134  				i = (i + 1) % (DaraTestPeers+1)
   135  				if i == 0 {
   136  					i=1
   137  				}
   138  				continue
   139  			} else {
   140  				peerAddrString := fmt.Sprintf(":666%d",i)
   141  				peerAddr, err := net.ResolveUDPAddr("udp",peerAddrString)
   142  				if err != nil {
   143  					logger.Panicf("Unable to resolve peer %s: %s",peerAddrString,err)
   144  				}
   145  				n, err := conn.WriteToUDP([]byte(h),peerAddr)
   146  				if err != nil {
   147  					logger.Panicf("Unable to write msg to peer %s",peerAddr.String())
   148  				}
   149  				logger.Printf("Writing: %x\t To: %s\t Len: %d\t",h,peerAddr.String(),n)
   150  				i = (i + 1) % (DaraTestPeers+1)
   151  				if i == 0 {
   152  					i=1
   153  				}
   154  			}
   155  			time.Sleep(time.Millisecond)
   156  		}
   157  	}
   158  	done<-true
   159  }
   160  
   161  func readhashmsg(tid int) {
   162  	logger.Printf("Reading Hashes on %d",tid)
   163  	buf := make([]byte,BUFSIZE)
   164  	for {
   165  		n, addr, err := conn.ReadFromUDP(buf)
   166  		if err != nil {
   167  			logger.Panicf("Error reading from udp %s",err.Error())
   168  		}
   169  		logger.Printf("Received: %x From %s Len %d",buf[:n],addr.String(),n)
   170  		recchan <- string(buf[:n])
   171  	}
   172  }
   173  
   174  func ParseEnviornment() {
   175  	var err error
   176  	DaraPIDString := os.Getenv("DARAPID")
   177  	if DaraPIDString == "" {
   178  		logger.Fatalf("DARAPID not set!")
   179  	}
   180  	DaraPID, err = strconv.Atoi(DaraPIDString)
   181  	if err != nil {
   182  		logger.Fatalf("DARAPID not a valid integer %s: %s",DaraPIDString,err.Error())
   183  	}
   184  
   185  	DaraTESTPEERSString := os.Getenv("DARATESTPEERS")
   186  	if DaraTESTPEERSString == "" {
   187  		logger.Fatalf("DARATESTPEERS not set!")
   188  	}
   189  	DaraTestPeers, err = strconv.Atoi(DaraTESTPEERSString)
   190  	if err != nil {
   191  		logger.Fatalf("DARATESTPEERS not a valid integer %s: %s",DaraTESTPEERSString,err.Error())
   192  	}
   193  	logger.Println("Done Parsing Enviornment")
   194  	return
   195  }
   196  
   197  func SetupUDPNetworkConnections() {
   198  	addrstring := fmt.Sprintf(":666%d",DaraPID)
   199  	addr, err := net.ResolveUDPAddr("udp",addrstring)
   200  	if err != nil {
   201  		logger.Fatal(err)
   202  	}
   203  	conn, err = net.ListenUDP("udp",addr)
   204  	if err != nil {
   205  		logger.Fatal(err)
   206  	}
   207  	logger.Println("Done Setting Up Network Connections")
   208  }
   209  
   210  
   211  
   212