コード例 #1
0
ファイル: gossip.go プロジェクト: cmars/conflux
func (p *Peer) handleReconRqstPoly(rp *ReconRqstPoly) *msgProgress {
	remoteSize := rp.Size
	points := p.ptree.Points()
	remoteSamples := rp.Samples
	node, err := p.ptree.Node(rp.Prefix)
	if err == ErrNodeNotFound {
		return &msgProgress{err: ErrReconRqstPolyNotFound}
	}
	localSamples := node.SValues()
	localSize := node.Size()
	remoteSet, localSet, err := p.solve(
		remoteSamples, localSamples, remoteSize, localSize, points)
	if errgo.Cause(err) == cf.ErrLowMBar {
		p.log(GOSSIP).Info("ReconRqstPoly: low MBar")
		if node.IsLeaf() || node.Size() < (p.settings.ThreshMult*p.settings.MBar) {
			p.logFields(GOSSIP, log.Fields{
				"node": node.Key(),
			}).Info("sending full elements")
			elements, err := node.Elements()
			if err != nil {
				return &msgProgress{err: errgo.Mask(err)}
			}
			return &msgProgress{elements: cf.NewZSet(), messages: []ReconMsg{
				&FullElements{ZSet: cf.NewZSet(elements...)}}}
		} else {
			err = errgo.Notef(err, "bs=%v leaf=%v size=%d", node.Key(), node.IsLeaf(), node.Size())
		}
	}
	if err != nil {
		p.logErr(GOSSIP, err).Info("ReconRqstPoly: sending SyncFail")
		return &msgProgress{elements: cf.NewZSet(), messages: []ReconMsg{&SyncFail{}}}
	}
	p.logFields(GOSSIP, log.Fields{"localSet": localSet, "remoteSet": remoteSet}).Info("ReconRqstPoly: solved")
	return &msgProgress{elements: remoteSet, messages: []ReconMsg{&Elements{ZSet: localSet}}}
}
コード例 #2
0
ファイル: runner.go プロジェクト: cmars/conflux
func (s *ReconSuite) RunOneSided(c *gc.C, n int, serverHas bool, timeout time.Duration) {
	ptree1, cleanup, err := s.Factory()
	c.Assert(err, gc.IsNil)
	defer cleanup()

	ptree2, cleanup, err := s.Factory()
	c.Assert(err, gc.IsNil)
	defer cleanup()

	expected := cf.NewZSet()

	for i := 1; i < n; i++ {
		z := cf.Zi(cf.P_SKS, 65537*i)
		ptree2.Insert(z)
		expected.Add(z)
	}

	port1, port2 := portPair(c)
	var peer1Mode recon.PeerMode
	var peer2Mode recon.PeerMode
	if serverHas {
		peer1Mode = recon.PeerModeGossipOnly
		peer2Mode = recon.PeerModeServeOnly
	} else {
		peer1Mode = recon.PeerModeServeOnly
		peer2Mode = recon.PeerModeGossipOnly
	}

	peer1 := s.newPeer(port1, port2, peer1Mode, ptree1)
	peer2 := s.newPeer(port2, port1, peer2Mode, ptree2)

	err = s.pollConvergence(c, peer1, peer2, expected, cf.NewZSet(), timeout)
	c.Assert(err, gc.IsNil)
}
コード例 #3
0
ファイル: peer.go プロジェクト: cmars/conflux
func (rwc *reconWithClient) sendRequest(p *Peer, req *requestEntry) error {
	if req == nil {
		return errgo.New("nil request")
	}

	var msg ReconMsg
	if req.node.IsLeaf() || (req.node.Size() < p.settings.MBar) {
		elements, err := req.node.Elements()
		if err != nil {
			return err
		}
		msg = &ReconRqstFull{
			Prefix:   req.key,
			Elements: cf.NewZSet(elements...)}
	} else {
		msg = &ReconRqstPoly{
			Prefix:  req.key,
			Size:    req.node.Size(),
			Samples: req.node.SValues()}
	}
	p.logFields(SERVE, log.Fields{"msg": msg}).Debug("sendRequest")
	rwc.messages = append(rwc.messages, msg)
	rwc.pushBottom(&bottomEntry{requestEntry: req})
	return nil
}
コード例 #4
0
ファイル: messages.go プロジェクト: cmars/conflux
func ReadZSet(r io.Reader) (*cf.ZSet, error) {
	arr, err := ReadZZarray(r)
	if err != nil {
		return nil, err
	}
	zset := cf.NewZSet()
	zset.AddSlice(arr)
	return zset, nil
}
コード例 #5
0
ファイル: runner.go プロジェクト: cmars/conflux
// Test sync with polynomial interpolation.
func (s *ReconSuite) TestPolySyncMBar(c *gc.C) {
	ptree1, cleanup, err := s.Factory()
	c.Assert(err, gc.IsNil)
	defer cleanup()

	ptree2, cleanup, err := s.Factory()
	c.Assert(err, gc.IsNil)
	defer cleanup()

	onlyInPeer1 := cf.NewZSet()
	// Load up peer 1 with items
	for i := 1; i < 100; i++ {
		ptree1.Insert(cf.Zi(cf.P_SKS, 65537*i))
	}
	// Four extra samples
	for i := 1; i < 5; i++ {
		z := cf.Zi(cf.P_SKS, 68111*i)
		ptree1.Insert(z)
		onlyInPeer1.Add(z)
	}
	root, _ := ptree1.Root()
	c.Log("peer1:", recon.MustElements(root))

	onlyInPeer2 := cf.NewZSet()
	// Load up peer 2 with items
	for i := 1; i < 100; i++ {
		ptree2.Insert(cf.Zi(cf.P_SKS, 65537*i))
	}
	// One extra sample
	for i := 1; i < 2; i++ {
		z := cf.Zi(cf.P_SKS, 70001*i)
		ptree2.Insert(z)
		onlyInPeer2.Add(z)
	}
	root, _ = ptree2.Root()
	c.Log("peer2:", recon.MustElements(root))

	port1, port2 := portPair(c)
	peer1 := s.newPeer(port1, port2, recon.PeerModeGossipOnly, ptree1)
	peer2 := s.newPeer(port2, port1, recon.PeerModeServeOnly, ptree2)

	err = s.pollConvergence(c, peer1, peer2, onlyInPeer2, onlyInPeer1, LongTimeout)
	c.Assert(err, gc.IsNil)
}
コード例 #6
0
ファイル: gossip.go プロジェクト: cmars/conflux
func (p *Peer) handleReconRqstFull(rf *ReconRqstFull) *msgProgress {
	var localset *cf.ZSet
	node, err := p.ptree.Node(rf.Prefix)
	if err == ErrNodeNotFound {
		localset = cf.NewZSet()
	} else if err != nil {
		return &msgProgress{err: err}
	} else {
		elements, err := node.Elements()
		if err != nil {
			return &msgProgress{err: err}
		}
		localset = cf.NewZSet(elements...)
	}
	localNeeds := cf.ZSetDiff(rf.Elements, localset)
	remoteNeeds := cf.ZSetDiff(localset, rf.Elements)
	p.logFields(GOSSIP, log.Fields{
		"localNeeds":  localNeeds.Len(),
		"remoteNeeds": remoteNeeds.Len(),
	}).Info("ReconRqstFull")
	return &msgProgress{elements: localNeeds, messages: []ReconMsg{&Elements{ZSet: remoteNeeds}}}
}
コード例 #7
0
ファイル: gossip.go プロジェクト: cmars/conflux
func (p *Peer) clientRecon(conn net.Conn, remoteConfig *Config) error {
	w := bufio.NewWriter(conn)
	respSet := cf.NewZSet()
	defer func() {
		p.sendItems(respSet.Items(), conn, remoteConfig)
	}()

	var pendingMessages []ReconMsg
	for step := range p.interactWithServer(conn) {
		if step.err != nil {
			if step.err == ErrReconDone {
				p.log(GOSSIP).Info("reconcilation done")
				break
			} else {
				err := WriteMsg(w, &Error{&textMsg{Text: step.err.Error()}})
				if err != nil {
					p.logErr(GOSSIP, err).Error()
				}
				p.logErr(GOSSIP, step.err).Error("step error")
				break
			}
		} else {
			pendingMessages = append(pendingMessages, step.messages...)
			if step.flush {
				for _, msg := range pendingMessages {
					err := WriteMsg(w, msg)
					if err != nil {
						return errgo.Mask(err)
					}
				}
				pendingMessages = nil

				err := w.Flush()
				if err != nil {
					return errgo.Mask(err)
				}
			}
		}
		p.log(GOSSIP).Debugf("add step: %v", step)
		respSet.AddAll(step.elements)
		p.log(GOSSIP).Infof("recover set now %d elements", respSet.Len())
	}
	return nil
}
コード例 #8
0
ファイル: peer.go プロジェクト: cmars/conflux
func (rwc *reconWithClient) handleReply(p *Peer, msg ReconMsg, req *requestEntry) error {
	rwc.Peer.logFields(SERVE, log.Fields{"msg": msg}).Debug("handleReply")
	switch m := msg.(type) {
	case *SyncFail:
		if req.node.IsLeaf() {
			return errgo.New("Syncfail received at leaf node")
		}
		rwc.Peer.log(SERVE).Debug("SyncFail: pushing children")
		children, err := req.node.Children()
		if err != nil {
			return errgo.Mask(err)
		}
		for i, childNode := range children {
			rwc.Peer.logFields(SERVE, log.Fields{"childNode": childNode.Key()}).Debug("push")
			if i == 0 {
				rwc.pushRequest(&requestEntry{key: childNode.Key(), node: childNode})
			} else {
				rwc.prependRequests(&requestEntry{key: childNode.Key(), node: childNode})
			}
		}
	case *Elements:
		rwc.rcvrSet.AddAll(m.ZSet)
	case *FullElements:
		elements, err := req.node.Elements()
		if err != nil {
			return err
		}
		local := cf.NewZSet(elements...)
		localNeeds := cf.ZSetDiff(m.ZSet, local)
		remoteNeeds := cf.ZSetDiff(local, m.ZSet)
		elementsMsg := &Elements{ZSet: remoteNeeds}
		rwc.Peer.logFields(SERVE, log.Fields{
			"msg": elementsMsg,
		}).Debug("handleReply: sending")
		rwc.messages = append(rwc.messages, elementsMsg)
		rwc.rcvrSet.AddAll(localNeeds)
	default:
		return errgo.Newf("unexpected message: %v", m)
	}
	return nil
}
コード例 #9
0
ファイル: ptree_test.go プロジェクト: cmars/conflux
func (s *PtreeSuite) TestJustOneKey(c *gc.C) {
	root, err := s.ptree.Root()
	c.Assert(err, gc.IsNil)
	s.ptree.Insert(cf.Zs(cf.P_SKS, "224045810486609649306292620830306652473"))
	expect := cf.NewZSet()
	for _, sv := range []string{
		"306467079064992673198834899522272784866",
		"306467079064992673198834899522272784865",
		"306467079064992673198834899522272784867",
		"306467079064992673198834899522272784864",
		"306467079064992673198834899522272784868",
		"306467079064992673198834899522272784863"} {
		expect.Add(cf.Zs(cf.P_SKS, sv))
	}
	c.Assert(err, gc.IsNil)
	root, err = s.ptree.Root()
	for _, sv := range root.SValues() {
		c.Assert(expect.Has(sv), gc.Equals, true, gc.Commentf("Unexpected svalue: %v", sv))
		expect.Remove(sv)
	}
	c.Assert(expect.Items(), gc.HasLen, 0)
}
コード例 #10
0
ファイル: gossip.go プロジェクト: cmars/conflux
func (p *Peer) interactWithServer(conn net.Conn) msgProgressChan {
	out := make(msgProgressChan)
	go func() {
		defer close(out)

		var resp *msgProgress
		var n int
		for (resp == nil || resp.err == nil) && n < maxRecoverSize {
			p.setReadDeadline(conn, defaultTimeout)
			msg, err := ReadMsg(conn)
			if err != nil {
				p.logErr(GOSSIP, err).Error("interact: read msg")
				out <- &msgProgress{err: err}
				return
			}
			p.logFields(GOSSIP, log.Fields{"msg": msg}).Debug("interact")
			switch m := msg.(type) {
			case *ReconRqstPoly:
				resp = p.handleReconRqstPoly(m)
			case *ReconRqstFull:
				resp = p.handleReconRqstFull(m)
			case *Elements:
				p.logFields(GOSSIP, log.Fields{"nelements": m.ZSet.Len()}).Debug()
				resp = &msgProgress{elements: m.ZSet}
			case *Done:
				resp = &msgProgress{err: ErrReconDone}
			case *Flush:
				resp = &msgProgress{elements: cf.NewZSet(), flush: true}
			default:
				resp = &msgProgress{err: errgo.Newf("unexpected message: %v", m)}
			}
			n += resp.elements.Len()
			out <- resp
		}
	}()
	return out
}
コード例 #11
0
ファイル: peer.go プロジェクト: cmars/conflux
func (p *Peer) interactWithClient(conn net.Conn, remoteConfig *Config, bitstring *cf.Bitstring) error {
	p.log(SERVE).Debug("interacting with client")
	p.setReadDeadline(conn, defaultTimeout)

	recon := reconWithClient{
		Peer:    p,
		conn:    conn,
		bwr:     bufio.NewWriter(conn),
		rcvrSet: cf.NewZSet(),
	}
	root, err := p.ptree.Root()
	if err != nil {
		return err
	}

	defer func() {
		p.sendItems(recon.rcvrSet.Items(), conn, remoteConfig)
	}()
	defer func() {
		WriteMsg(recon.bwr, &Done{})
	}()

	recon.pushRequest(&requestEntry{node: root, key: bitstring})
	for !recon.isDone() {
		bottom := recon.topBottom()
		p.logFields(SERVE, log.Fields{"bottom": bottom}).Debug("interact")
		switch {
		case bottom == nil:
			req := recon.popRequest()
			p.logFields(SERVE, log.Fields{
				"popRequest": req,
			}).Debug("interact: sending...")
			err = recon.sendRequest(p, req)
			if err != nil {
				return err
			}
		case bottom.state == reconStateFlushEnded:
			p.log(SERVE).Debug("interact: flush ended, popBottom")
			recon.popBottom()
			recon.flushing = false
		case bottom.state == reconStateBottom:
			p.logFields(SERVE, log.Fields{
				"queueLength": len(recon.bottomQ),
			}).Debug()
			var msg ReconMsg
			var hasMsg bool

			// Set a small read timeout to simulate non-blocking I/O
			p.setReadDeadline(conn, time.Millisecond)
			if err != nil {
				return errgo.Mask(err)
			}
			msg, nbErr := ReadMsg(conn)
			hasMsg = (nbErr == nil)

			// Restore blocking I/O
			p.setReadDeadline(conn, defaultTimeout)
			if err != nil {
				return errgo.Mask(err)
			}

			if hasMsg {
				recon.popBottom()
				err = recon.handleReply(p, msg, bottom.requestEntry)
				if err != nil {
					return errgo.Mask(err)
				}
			} else if len(recon.bottomQ) > p.settings.MaxOutstandingReconRequests ||
				len(recon.requestQ) == 0 {
				if !recon.flushing {
					err = recon.flushQueue()
					if err != nil {
						return errgo.Mask(err)
					}
				} else {
					recon.popBottom()
					p.setReadDeadline(conn, 3*time.Second)
					msg, err = ReadMsg(conn)
					if err != nil {
						return errgo.Mask(err)
					}
					p.logFields(SERVE, log.Fields{"msg": msg}).Debug("reply")
					err = recon.handleReply(p, msg, bottom.requestEntry)
					if err != nil {
						return errgo.Mask(err)
					}
				}
			} else {
				req := recon.popRequest()
				err = recon.sendRequest(p, req)
				if err != nil {
					return err
				}
			}
		default:
			return errgo.New("failed to match expected patterns")
		}
	}
	return nil
}
コード例 #12
0
ファイル: runner.go プロジェクト: cmars/conflux
func (s *ReconSuite) pollRootConvergence(c *gc.C, peer1, peer2 *recon.Peer, ptree1, ptree2 recon.PrefixTree) error {
	var t tomb.Tomb
	t.Go(func() error {
		defer peer1.Stop()
		defer peer2.Stop()

		var mu sync.Mutex
		var zs1 *cf.ZSet = cf.NewZSet()
		var zs2 *cf.ZSet = cf.NewZSet()

		timer := time.NewTimer(LongTimeout)
		peer1.SetMutatedFunc(func() {
			mu.Lock()
			root1, err := ptree1.Root()
			c.Assert(err, gc.IsNil)
			zs1 = cf.NewZSet(recon.MustElements(root1)...)
			mu.Unlock()
		})
		peer2.SetMutatedFunc(func() {
			mu.Lock()
			root2, err := ptree2.Root()
			c.Assert(err, gc.IsNil)
			zs2 = cf.NewZSet(recon.MustElements(root2)...)
			mu.Unlock()
		})
	POLLING:
		for {
			select {
			case r1, ok := <-peer1.RecoverChan:
				if !ok {
					break POLLING
				}
				c.Logf("peer1 recover: %v", r1)
				for _, zp := range r1.RemoteElements {
					c.Assert(zp, gc.NotNil)
					peer1.Insert(zp)
				}
			case r2, ok := <-peer2.RecoverChan:
				if !ok {
					break POLLING
				}
				c.Logf("peer2 recover: %v", r2)
				for _, zp := range r2.RemoteElements {
					c.Assert(zp, gc.NotNil)
					peer2.Insert(zp)
				}
			case _ = <-timer.C:
				return fmt.Errorf("timeout waiting for convergence")
			default:
			}

			var done bool
			mu.Lock()
			done = zs1.Len() > 0 && zs1.Equal(zs2)
			mu.Unlock()
			if done {
				c.Logf("peer1 has %q, peer2 has %q", zs1, zs2)
				return nil
			}
		}
		return fmt.Errorf("set reconciliation did not converge")
	})
	return t.Wait()
}
コード例 #13
0
ファイル: ptree.go プロジェクト: cmars/conflux
// Init configures the tree with default settings if not already set,
// and initializes the internal state with sample data points, root node, etc.
func (t *MemPrefixTree) Init() {
	t.PTreeConfig = defaultPTreeConfig
	t.points = cf.Zpoints(cf.P_SKS, t.NumSamples())
	t.allElements = cf.NewZSet()
	t.Create()
}