Beispiel #1
0
// start is the seqn at which this member was defined.
// start+alpha is the first seqn this manager is expected to participate in.
func NewManager(self string, alpha int, st *store.Store, outs PutterTo) *Manager {
	start := <-st.Seqns
	m := &Manager{
		st:        st,
		ops:       st.Ops,
		rg:        NewRegistrar(st, start, alpha),
		seqns:     make(chan uint64),
		fillUntil: make(chan uint64),
		reqs:      make(chan instReq),
		logger:    util.NewLogger("manager"),
		Self:      self,
		alpha:     alpha,
		outs:      outs,
	}

	go m.gen(start + uint64(alpha))
	go m.fill(start + uint64(alpha))
	go m.process()

	// Wait until process is ready
	// TODO: is there something we can do to avoid this?
	m.getInstance(0)

	return m
}
Beispiel #2
0
func Dial(addr string) (*Client, os.Error) {
	c, err := net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}
	pr := proto.NewConn(c)
	go pr.ReadResponses()
	return &Client{pr: pr, lg: util.NewLogger(addr)}, nil
}
Beispiel #3
0
func Clean(st *store.Store) {
	cl := &cleaner{
		st:     st,
		table:  make(map[string]uint64),
		logger: util.NewLogger("clean"),
	}

	for ev := range st.Watch("/doozer/info/*/applied") {
		cl.update(ev)
		cl.check()
	}
}
Beispiel #4
0
func (st *Store) process(ops <-chan Op, seqns chan<- uint64, watches chan<- int) {
	logger := util.NewLogger("store")
	defer st.closeWatches()

	var head uint64

	for {
		ver, values := st.state.ver, st.state.root

		// Take any incoming requests and queue them up.
		select {
		case a := <-ops:
			if closed(ops) {
				return
			}

			if a.Seqn > ver {
				st.todo[a.Seqn] = a
			}
		case w := <-st.watchCh:
			st.watches = append(st.watches, w)
		case seqn := <-st.cleanCh:
			for ; head <= seqn; head++ {
				st.log[head] = Event{}, false
			}
		case seqns <- ver:
			// nothing to do here
		case watches <- len(st.watches):
			// nothing to do here
		case st.notices[0].ch <- st.notices[0].ev:
			st.notices = st.notices[1:]

			if len(st.notices) < 1 {
				st.notices = make([]notice, 1)
			}
		}

		// If we have any mutations that can be applied, do them.
		for t, ok := st.todo[ver+1]; ok; t, ok = st.todo[ver+1] {
			var ev Event
			values, ev = values.apply(t.Seqn, t.Mut)
			logger.Printf("apply %s %v %v %v %v %v", ev.Desc(), ev.Seqn, ev.Path, ev.Body, ev.Cas, ev.Err)
			st.state = &state{ev.Seqn, values}
			st.log[t.Seqn] = ev
			st.notify(ev)
			for ver < ev.Seqn {
				ver++
				st.todo[ver] = Op{}, false
			}
		}
	}
}
Beispiel #5
0
func newService(id, name string, mon *monitor) *service {
	sv := &service{
		id:     id,
		name:   name,
		st:     mon.st,
		self:   mon.self,
		cl:     mon.cl,
		mon:    mon,
		logger: util.NewLogger(id),
	}
	sv.logger.Println("new")
	return sv
}
Beispiel #6
0
func (c *conn) serve() {
	logger := util.NewLogger("%v", c.c.RemoteAddr())
	logger.Println("accepted connection")
	for {
		rid, verb, data, err := c.ReadRequest()
		if err != nil {
			if err == os.EOF {
				logger.Println("connection closed by peer")
			} else {
				logger.Println(err)
			}
			return
		}

		rlogger := util.NewLogger("%v - req [%d]", c.c.RemoteAddr(), rid)

		if o, ok := ops[verb]; ok {
			rlogger.Printf("%s %v", verb, data)

			err := proto.Fit(data, o.p)
			if err != nil {
				c.SendResponse(rid, proto.Last, err)
				continue
			}

			if o.redirect && !c.cal {
				c.redirect(rid)
				continue
			}

			go c.handle(rid, o.f, indirect(o.p))
			continue
		}

		rlogger.Printf("unknown command <%s>", verb)
		c.SendResponse(rid, proto.Last, os.ErrorString(proto.InvalidCommand+" "+verb))
	}
}
Beispiel #7
0
// This is a little subtle. We want to follow redirects while still pipelining
// requests, and we want to allow as many requests as possible to succeed
// without retrying unnecessarily.
//
// In particular, reads never need to redirect, and writes must always go to
// the leader. So we want that read requests never retry, and write requests
// retry if and only if necessary. Here's how it works:
//
// In the proto.Conn, when we get a redirect response, we raise a flag noting
// the new address. This flag only goes up, never down. This flag effectively
// means the connection is deprecated. Any pending requests can go ahead, but
// new requests should use the new address.
//
// In the Client, when we notice that a redirect has occurred (i.e. the flag is
// set), we establish a new connection to the new address. Calls in the future
// will use the new connection. But we also allow the old connection to
// continue functioning as it was. Any writes on the old connection will retry,
// and then they are guaranteed to pick up the new connection. Any reads on the
// old connection will just succeed directly.
func (cl *Client) proto() (*proto.Conn, os.Error) {
	cl.lk.Lock()
	defer cl.lk.Unlock()

	if cl.pr.RedirectAddr != "" {
		conn, err := net.Dial("tcp", "", cl.pr.RedirectAddr)
		if err != nil {
			return nil, err
		}
		cl.lg = util.NewLogger(cl.pr.RedirectAddr)
		cl.pr = proto.NewConn(conn)
		go cl.pr.ReadResponses()
	}

	return cl.pr, nil
}
Beispiel #8
0
func Clean(st *store.Store, p paxos.Proposer) {
	logger := util.NewLogger("member")
	for ev := range st.Watch("/session/*") {
		if !ev.IsDel() {
			continue
		}

		parts := strings.Split(ev.Path, "/", 3)
		name := parts[2]
		logger.Printf("lost session %s", name)

		clearSlot(p, ev, name)
		removeMember(p, ev, name)
		removeInfo(p, ev, name)
	}
}
Beispiel #9
0
func activate(st *store.Store, self string, c *client.Client, cal chan int) {
	logger := util.NewLogger("activate")
	ch := make(chan store.Event)
	st.GetDirAndWatch("/doozer/slot", ch)
	for ev := range ch {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(ev.Path, self, ev.Cas)
			if err != nil {
				logger.Println(err)
				continue
			}
			close(cal)
			close(ch)
		}
	}
}
Beispiel #10
0
func newSocket(id, name string, mon *monitor) *socket {
	sv := mon.increfService(name + ".service")
	if sv == nil {
		return nil
	}

	so := &socket{
		id:     id,
		name:   name,
		st:     mon.st,
		self:   mon.self,
		cl:     mon.cl,
		sv:     sv,
		mon:    mon,
		logger: util.NewLogger(id),
	}
	so.logger.Println("new")
	return so
}
Beispiel #11
0
func evServer(w http.ResponseWriter, r *http.Request) {
	wevs := make(chan store.Event)
	logger := util.NewLogger(w.RemoteAddr())
	path := r.URL.Path[len(evPrefix):]
	logger.Println("new", path)

	evs := Store.Watch(path + "**")

	// TODO convert store.Snapshot to json and use that
	go func() {
		walk(path, Store, wevs)
		close(wevs)
	}()

	websocket.Handler(func(ws *websocket.Conn) {
		send(ws, path, wevs, logger)
		send(ws, path, evs, logger)
		ws.Close()
	}).ServeHTTP(w, r)
}
Beispiel #12
0
func Pulse(node string, seqns <-chan uint64, s Setter, sleep int64) {
	logger := util.NewLogger("pulse")

	var err os.Error
	cas := store.Missing

	for {
		seqn := strconv.Uitoa64(<-seqns)
		if closed(seqns) {
			break
		}

		cas, err = s.Set("/doozer/info/"+node+"/applied", seqn, cas)
		if err != nil {
			logger.Println(err)
		}

		time.Sleep(sleep)
	}
}
Beispiel #13
0
func Clean(st *store.Store, pp paxos.Proposer) {
	logger := util.NewLogger("lock")
	for ev := range st.Watch("/session/*") {
		if !ev.IsDel() {
			continue
		}

		parts := strings.Split(ev.Path, "/", 3)
		name := parts[2]
		logger.Printf("lost session %s", name)

		ch, err := store.Walk(ev, "/lock/**")
		if err != nil {
			continue
		}

		for ev := range ch {
			if ev.Body == name {
				paxos.Del(pp, ev.Path, ev.Cas)
			}
		}
	}
}
Beispiel #14
0
	errPrefix      = "ERR:"
)

var (
	ErrClosed = os.NewError("response was closed")
)

// Response flags
const (
	Closed = 1 << iota
	Last
)

var crnl = []byte{'\r', '\n'}

var logger = util.NewLogger("proto")

type Line string

type Redirect string

// This is to satisfy os.Error.
func (r Redirect) String() string {
	return string(r)
}

// This needs to be refactored. There is client stuff and server stuff mixed up
// in here. This type should contain only symmetric low-level connection stuff.
type Conn struct {
	c  io.ReadWriteCloser
	r  *bufio.Reader
Beispiel #15
0
func Monitor(self string, st *store.Store, cl SetDeler) os.Error {

	mon := &monitor{
		self:    self,
		st:      st,
		cl:      cl,
		clock:   make(chan ticker),
		units:   make(map[string]unit),
		refs:    make(map[string]int),
		exitCh:  make(chan exit),
		readyCh: make(chan ready),
		logger:  util.NewLogger("monitor"),
	}

	mon.logger.Println("reading units")
	evs := make(chan store.Event)
	st.GetDirAndWatch(ctlKey, evs)
	go func(c <-chan store.Event) {
		for e := range c {
			evs <- e
		}
		close(evs)
	}(st.Watch(lockKey + "/*"))

	for {
		select {
		case t := <-mon.clock:
			t.tick()
		case ev := <-evs:
			prefix, id := path.Split(ev.Path)
			switch prefix {
			case ctlDir:
				if ev.IsDel() {
					mon.logger.Println("\n\n\ndel", id)
					mon.decrefUnit(id)
					break
				}

				ut := mon.increfUnit(id)
				if ut == nil {
					break
				}

				switch ev.Body {
				case "start":
					ut.start()
				case "stop":
					ut.stop()
				case "auto", "":
					fallthrough
				default:
					// nothing
				}

			case lockDir:
				ut := mon.units[id]
				if ut == nil {
					break
				}

				ut.dispatchLockEvent(ev)
			}
		case e := <-mon.exitCh:
			e.e.exited(e.w)
		case r := <-mon.readyCh:
			r.r.ready(r.f)
		}
	}
	panic("unreachable")
}
Beispiel #16
0
func Main(clusterName, attachAddr string, udpConn net.PacketConn, listener, webListener net.Listener) {
	logger := util.NewLogger("main")

	var err os.Error

	listenAddr := listener.Addr().String()

	outs := make(paxos.ChanPutCloserTo)

	cal := make(chan int)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	if attachAddr == "" { // we are the only node in a new cluster
		set(st, "/doozer/info/"+self+"/public-addr", listenAddr, store.Missing)
		set(st, "/doozer/info/"+self+"/hostname", os.Getenv("HOSTNAME"), store.Missing)
		set(st, "/doozer/members/"+self, listenAddr, store.Missing)
		set(st, "/doozer/slot/"+"1", self, store.Missing)
		set(st, "/doozer/leader", self, store.Missing)
		set(st, "/ping", "pong", store.Missing)

		close(cal)

		cl, err = client.Dial(listenAddr)
		if err != nil {
			panic(err)
		}
	} else {
		cl, err = client.Dial(attachAddr)
		if err != nil {
			panic(err)
		}

		path := "/doozer/info/" + self + "/public-addr"
		_, err = cl.Set(path, listenAddr, store.Clobber)
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/hostname"
		_, err = cl.Set(path, os.Getenv("HOSTNAME"), store.Clobber)
		if err != nil {
			panic(err)
		}

		joinSeqn, snap, err := cl.Join(self, listenAddr)
		if err != nil {
			panic(err)
		}

		done := make(chan int)
		st.Ops <- store.Op{1, snap}

		go advanceUntil(cl, done)

		go func() {
			st.Sync(joinSeqn + alpha)
			close(done)
			activate(st, self, cl, cal)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}

	mg := paxos.NewManager(self, alpha, st, outs)

	if attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		n := <-st.Seqns
		for i := n + 1; i < n+alpha; i++ {
			st.Ops <- store.Op{i, store.Nop}
		}
	}

	go func() {
		<-cal
		go lock.Clean(st, mg)
		go session.Clean(st, mg)
		go member.Clean(st, mg)
		go gc.Pulse(self, st.Seqns, cl, pulseInterval)
		go gc.Clean(st)
	}()

	sv := &server.Server{udpConn, listenAddr, st, mg, self}

	go func() {
		cas := store.Missing
		for _ = range time.Tick(checkinInterval) {
			_, cas, err = cl.Checkin(self, cas)
			if err != nil {
				logger.Println(err)
			}
		}
	}()

	go func() {
		err := sv.Serve(listener, cal)
		if err != nil {
			panic(err)
		}
	}()

	if webListener != nil {
		web.Store = st
		web.ClusterName = clusterName
		go web.Serve(webListener)
	}

	sv.ServeUdp(outs)
}
Beispiel #17
0
	"doozer/paxos"
	"doozer/util"
	"math"
	"net"
	"os"
	"time"
)

const (
	interval = 1e8  // ns == 100ms
	timeout  = 1e10 // ns == 10s

	max = 3000 // bytes. Definitely big enough for UDP over Ethernet.
)

var logger = util.NewLogger("net")

type Conn interface {
	ReadFrom([]byte) (int, net.Addr, os.Error)
	WriteTo([]byte, net.Addr) (int, os.Error)
	LocalAddr() net.Addr
}

type check struct {
	paxos.Packet
	at, until int64
}

func (k check) Less(y interface{}) bool {
	return k.at < y.(check).at
}
Beispiel #18
0
	Conn net.PacketConn
	Addr string
	St   *store.Store
	Mg   Manager
	Self string
}

func (sv *Server) ServeUdp(outs chan paxos.Packet) {
	r := dnet.Ackify(sv.Conn, outs)

	for p := range r {
		sv.Mg.PutFrom(p.Addr, p.Msg)
	}
}

var clg = util.NewLogger("cal")

func (s *Server) Serve(l net.Listener, cal chan int) os.Error {
	for {
		rw, err := l.Accept()
		if err != nil {
			log.Printf("%#v", err)
			if e, ok := err.(*net.OpError); ok && e.Error == os.EINVAL {
				return nil
			}
			return err
		}
		c := &conn{proto.NewConn(rw), rw, s, closed(cal)}
		go c.serve()
	}