Exemple #1
0
func (s *GraphStore) insert(e *spb.Entry) {
	i := sort.Search(len(s.entries), func(i int) bool {
		return compare.Entries(e, s.entries[i]) == compare.LT
	})
	if i == len(s.entries) {
		s.entries = append(s.entries, e)
	} else if i < len(s.entries) && compare.EntriesEqual(e, s.entries[i]) {
		s.entries[i] = e
	} else if i == 0 {
		s.entries = append([]*spb.Entry{e}, s.entries...)
	} else {
		s.entries = append(s.entries[:i], append([]*spb.Entry{e}, s.entries[i:]...)...)
	}
}
Exemple #2
0
// invoke calls req concurrently for each delegated service in p, merges the
// results, and delivers them to f.
func (p *proxyService) invoke(req func(graphstore.Service, graphstore.EntryFunc) error, f graphstore.EntryFunc) error {
	stop := make(chan struct{}) // Closed to signal cancellation

	// Create a channel for each delegated request, and a callback that
	// delivers results to that channel.  The callback will handle cancellation
	// signaled by a close of the stop channel, and exit early.

	rcv := make([]graphstore.EntryFunc, len(p.stores)) // callbacks
	chs := make([]chan *spb.Entry, len(p.stores))      // channels
	for i := range p.stores {
		ch := make(chan *spb.Entry)
		chs[i] = ch
		rcv[i] = func(e *spb.Entry) error {
			select {
			case <-stop: // cancellation has been signalled
				return nil
			case ch <- e:
				return nil
			}
		}
	}

	// Invoke the requests for each service, using the corresponding callback.
	errc := p.foreach(func(i int, s graphstore.Service) error {
		err := req(s, rcv[i])
		close(chs[i])
		return err
	})

	// Accumulate and merge the results.  This is a straightforward round-robin
	// n-finger merge of the values from the delegated requests.

	var h compare.ByEntries // used to preserve stream order
	var last *spb.Entry     // used to deduplicate entries
	var perr error          // error while accumulating
	go func() {
		defer close(stop)
		for {
			hit := false // are any requests still pending?

			// Give each channel a chance to produce a value, round-robin to
			// preserve the global ordering.
			for _, ch := range chs {
				if e, ok := <-ch; ok {
					hit = true
					heap.Push(&h, e)
				}
			}

			// If there are any values pending, deliver one to the consumer.
			// If not, and there are no more values coming, we're finished.
			if h.Len() != 0 {
				entry := heap.Pop(&h).(*spb.Entry)
				if last == nil || !compare.EntriesEqual(last, entry) {
					last = entry
					if err := f(entry); err != nil {
						if err != io.EOF {
							perr = err
						}
						return
					}
				}
			} else if !hit {
				return // no more work to do
			}
		}
	}()
	err := waitErr(errc) // wait for all receives to complete
	<-stop               // wait for all sends to complete
	if perr != nil {
		return perr
	}
	return err
}