Exemple #1
0
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
}
Exemple #2
0
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
}
Exemple #3
0
func subscriber(srv *clonesrv_t) (err error) {
	//  Get state snapshot if necessary
	if !srv.kvmap_init {
		srv.kvmap_init = true
		snapshot, _ := zmq.NewSocket(zmq.DEALER)
		snapshot.Connect(fmt.Sprint("tcp://localhost:", srv.peer))
		fmt.Printf("I: asking for snapshot from: tcp://localhost:%v\n", srv.peer)
		snapshot.SendMessage("ICANHAZ?", "") // blank subtree to get all
		for {
			kvmsg, e := kvmsg.RecvKvmsg(snapshot)
			if e != nil {
				err = e
				break
			}
			if key, _ := kvmsg.GetKey(); key == "KTHXBAI" {
				srv.sequence, _ = kvmsg.GetSequence()
				break //  Done
			}
			kvmsg.Store(srv.kvmap)
		}
		fmt.Println("I: received snapshot =", srv.sequence)
	}
	//  Find and remove update off pending list
	kvmsg, e := kvmsg.RecvKvmsg(srv.subscriber)
	if e != nil {
		err = e
		return
	}

	if key, _ := kvmsg.GetKey(); key != "HUGZ" {
		if !srv.was_pending(kvmsg) {
			//  If active update came before client update, flip it
			//  around, store active update (with sequence) on pending
			//  list and use to clear client update when it comes later
			srv.pending = append(srv.pending, kvmsg)
		}
		//  If update is more recent than our kvmap, apply it
		if seq, _ := kvmsg.GetSequence(); seq > srv.sequence {
			srv.sequence = seq
			kvmsg.Store(srv.kvmap)
			fmt.Println("I: received update =", srv.sequence)
		}
	}
	return
}
Exemple #4
0
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
}
Exemple #5
0
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
}
Exemple #6
0
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)
}
Exemple #7
0
func clone_agent(pipename string) {

	pipe, _ := zmq.NewSocket(zmq.PAIR)
	pipe.Connect(pipename)

	agent := agent_new(pipe)

LOOP:
	for {
		poller := zmq.NewPoller()
		poller.Add(pipe, zmq.POLLIN)
		server := agent.server[agent.cur_server]
		switch agent.state {
		case state_INITIAL:
			//  In this state we ask the server for a snapshot,
			//  if we have a server to talk to...
			if agent.nbr_servers > 0 {
				fmt.Printf("I: waiting for server at %s:%d...\n", server.address, server.port)
				if server.requests < 2 {
					server.snapshot.SendMessage("ICANHAZ?", agent.subtree)
					server.requests++
				}
				server.expiry = time.Now().Add(server_TTL)
				agent.state = state_SYNCING
				poller.Add(server.snapshot, zmq.POLLIN)
			}

		case state_SYNCING:
			//  In this state we read from snapshot and we expect
			//  the server to respond, else we fail over.
			poller.Add(server.snapshot, zmq.POLLIN)

		case state_ACTIVE:
			//  In this state we read from subscriber and we expect
			//  the server to give hugz, else we fail over.
			poller.Add(server.subscriber, zmq.POLLIN)
			break
		}
		poll_timer := time.Duration(-1)
		if server != nil {
			poll_timer = server.expiry.Sub(time.Now())
			if poll_timer < 0 {
				poll_timer = 0
			}
		}
		//  We're ready to process incoming messages; if nothing at all
		//  comes from our server within the timeout, that means the
		//  server is dead:

		polled, err := poller.Poll(poll_timer)
		if err != nil {
			break
		}

		if len(polled) > 0 {
			for _, item := range polled {
				switch socket := item.Socket; socket {
				case pipe:

					err = agent.control_message()
					if err != nil {
						break LOOP
					}

				default:
					kvmsg, e := kvmsg.RecvKvmsg(socket)
					if e != nil {
						err = e
						break LOOP
					}

					//  Anything from server resets its expiry time
					server.expiry = time.Now().Add(server_TTL)
					if agent.state == state_SYNCING {
						//  Store in snapshot until we're finished
						server.requests = 0
						if key, _ := kvmsg.GetKey(); key == "KTHXBAI" {
							agent.sequence, _ = kvmsg.GetSequence()
							agent.state = state_ACTIVE
							fmt.Printf("I: received from %s:%d snapshot=%d\n", server.address, server.port, agent.sequence)
						} else {
							kvmsg.Store(agent.kvmap)
						}
					} else if agent.state == state_ACTIVE {
						//  Discard out-of-sequence updates, incl. hugz
						if seq, _ := kvmsg.GetSequence(); seq > agent.sequence {
							agent.sequence = seq
							kvmsg.Store(agent.kvmap)
							fmt.Printf("I: received from %s:%d update=%d\n", server.address, server.port, agent.sequence)
						}
					}
				}
			}
		} else {
			//  Server has died, failover to next
			fmt.Printf("I: server at %s:%d didn't give hugz\n", server.address, server.port)
			agent.cur_server = (agent.cur_server + 1) % agent.nbr_servers
			agent.state = state_INITIAL
		}
	}
}