func snapshots(socket *zmq.Socket, srv *clonesrv_t) (err error) { msg, err := socket.RecvMessage(0) if err != nil { return } identity := msg[0] // Request is in second frame of message request := msg[1] if request != "ICANHAZ?" { err = errors.New("E: bad request, aborting") return } subtree := msg[2] // Send state socket to client for _, kvmsg := range srv.kvmap { if key, _ := kvmsg.GetKey(); strings.HasPrefix(key, subtree) { socket.Send(identity, zmq.SNDMORE) kvmsg.Send(socket) } } // Now send END message with sequence number log.Println("I: sending shapshot =", srv.sequence) socket.Send(identity, zmq.SNDMORE) kvmsg := kvmsg.NewKvmsg(srv.sequence) kvmsg.SetKey("KTHXBAI") kvmsg.SetBody(subtree) kvmsg.Send(socket) return }
func flush_ttl(srv *clonesrv_t) (err error) { for _, kvmsg := range srv.kvmap { // If key-value pair has expired, delete it and publish the // fact to listening clients. if ttls, e := kvmsg.GetProp("ttl"); e == nil { ttl, e := strconv.ParseInt(ttls, 10, 64) if e != nil { err = e continue } if time.Now().After(time.Unix(ttl, 0)) { srv.sequence++ kvmsg.SetSequence(srv.sequence) kvmsg.SetBody("") e = kvmsg.Send(srv.publisher) if e != nil { err = e } kvmsg.Store(srv.kvmap) log.Println("I: publishing delete =", srv.sequence) } } } return }
func collector(srv *clonesrv_t) (err error) { kvmsg, err := kvmsg.RecvKvmsg(srv.collector) if err != nil { return } if srv.active { srv.sequence++ kvmsg.SetSequence(srv.sequence) kvmsg.Send(srv.publisher) if ttls, e := kvmsg.GetProp("ttl"); e == nil { ttl, e := strconv.ParseInt(ttls, 10, 64) if e != nil { err = e return } kvmsg.SetProp("ttl", fmt.Sprint(time.Now().Add(time.Duration(ttl)*time.Second).Unix())) } kvmsg.Store(srv.kvmap) log.Println("I: publishing update =", srv.sequence) } else { // If we already got message from active, drop it, else // hold on pending list if !srv.was_pending(kvmsg) { srv.pending = append(srv.pending, kvmsg) } } return }
func send_hugz(srv *clonesrv_t) (err error) { kvmsg := kvmsg.NewKvmsg(srv.sequence) kvmsg.SetKey("HUGZ") kvmsg.SetBody("") err = kvmsg.Send(srv.publisher) return }
func (agent *agent_t) control_message() (err error) { msg, e := agent.pipe.RecvMessage(0) if e != nil { return e } command := msg[0] msg = msg[1:] switch command { case "SUBTREE": agent.subtree = msg[0] case "CONNECT": address := msg[0] service := msg[1] if agent.nbr_servers < server_MAX { serv, _ := strconv.Atoi(service) agent.server[agent.nbr_servers] = server_new(address, serv, agent.subtree) agent.nbr_servers++ // We broadcast updates to all known servers agent.publisher.Connect(fmt.Sprintf("%s:%d", address, serv+2)) } else { fmt.Printf("E: too many servers (max. %d)\n", server_MAX) } case "SET": // When we set a property, we push the new key-value pair onto // all our connected servers: key := msg[0] value := msg[1] ttl := msg[2] // Send key-value pair on to server kvmsg := kvmsg.NewKvmsg(0) kvmsg.SetKey(key) kvmsg.SetUuid() kvmsg.SetBody(value) kvmsg.SetProp("ttl", ttl) kvmsg.Store(agent.kvmap) kvmsg.Send(agent.publisher) case "GET": key := msg[0] value := "" if kvmsg, ok := agent.kvmap[key]; ok { value, _ = kvmsg.GetBody() } agent.pipe.SendMessage(value) } return }
func collector(srv *clonesrv_t) (err error) { kvmsg, err := kvmsg.RecvKvmsg(srv.collector) if err != nil { return } srv.sequence++ kvmsg.SetSequence(srv.sequence) kvmsg.Send(srv.publisher) if ttls, e := kvmsg.GetProp("ttl"); e == nil { // change duration into specific time, using the same property: ugly! ttl, e := strconv.ParseInt(ttls, 10, 64) if e != nil { err = e return } kvmsg.SetProp("ttl", fmt.Sprint(time.Now().Add(time.Duration(ttl)*time.Second).Unix())) } kvmsg.Store(srv.kvmap) log.Println("I: publishing update =", srv.sequence) return }
func main() { snapshot, _ := zmq.NewSocket(zmq.DEALER) snapshot.Connect("tcp://localhost:5556") subscriber, _ := zmq.NewSocket(zmq.SUB) subscriber.SetSubscribe(SUBTREE) subscriber.Connect("tcp://localhost:5557") publisher, _ := zmq.NewSocket(zmq.PUSH) publisher.Connect("tcp://localhost:5558") kvmap := make(map[string]*kvmsg.Kvmsg) rand.Seed(time.Now().UnixNano()) // We first request a state snapshot: sequence := int64(0) snapshot.SendMessage("ICANHAZ?", SUBTREE) for { kvmsg, err := kvmsg.RecvKvmsg(snapshot) if err != nil { break // Interrupted } if key, _ := kvmsg.GetKey(); key == "KTHXBAI" { sequence, _ := kvmsg.GetSequence() fmt.Println("I: received snapshot =", sequence) break // Done } kvmsg.Store(kvmap) } snapshot.Close() poller := zmq.NewPoller() poller.Add(subscriber, zmq.POLLIN) alarm := time.Now().Add(1000 * time.Millisecond) for { tickless := alarm.Sub(time.Now()) if tickless < 0 { tickless = 0 } polled, err := poller.Poll(tickless) if err != nil { break // Context has been shut down } if len(polled) == 1 { kvmsg, err := kvmsg.RecvKvmsg(subscriber) if err != nil { break // Interrupted } // Discard out-of-sequence kvmsgs, incl. heartbeats if seq, _ := kvmsg.GetSequence(); seq > sequence { sequence = seq kvmsg.Store(kvmap) fmt.Println("I: received update =", sequence) } } // If we timed-out, generate a random kvmsg if time.Now().After(alarm) { kvmsg := kvmsg.NewKvmsg(0) kvmsg.SetKey(fmt.Sprintf("%s%d", SUBTREE, rand.Intn(10000))) kvmsg.SetBody(fmt.Sprint(rand.Intn(1000000))) kvmsg.SetProp("ttl", fmt.Sprintf("%d", rand.Intn((30)))) // seconds kvmsg.Send(publisher) alarm = time.Now().Add(1000 * time.Millisecond) } } fmt.Printf("Interrupted\n%d messages in\n", sequence) }