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