func doWatch(stream etcdserverpb.Watch_WatchClient, requests <-chan *etcdserverpb.WatchRequest) { for r := range requests { st := time.Now() err := stream.Send(r) var errStr string if err != nil { errStr = err.Error() } results <- &result{ errStr: errStr, duration: time.Since(st), } bar.Increment() } wg.Done() for { _, err := stream.Recv() var errStr string if err != nil { errStr = err.Error() } results <- &result{ errStr: errStr, } bar.Increment() } }
func doWatch(stream etcdserverpb.Watch_WatchClient, requests <-chan etcdserverpb.WatchRequest) { for r := range requests { st := time.Now() err := stream.Send(&r) var errStr string if err != nil { errStr = err.Error() } results <- result{errStr: errStr, duration: time.Since(st)} bar.Increment() } atomic.AddInt32(&nrWatchCompleted, 1) if atomic.LoadInt32(&nrWatchCompleted) == int32(watchTotalStreams) { watchCompletedNotifier <- struct{}{} } <-putStartNotifier for { st := time.Now() _, err := stream.Recv() var errStr string if err != nil { errStr = err.Error() } results <- result{errStr: errStr, duration: time.Since(st)} bar.Increment() atomic.AddInt32(&nrRecvCompleted, 1) if atomic.LoadInt32(&nrRecvCompleted) == int32(eventsTotal) { recvCompletedNotifier <- struct{}{} } } }
func recvLoop(wStream pb.Watch_WatchClient) { for { resp, err := wStream.Recv() if err == io.EOF { os.Exit(ExitSuccess) } if err != nil { ExitWithError(ExitError, err) } fmt.Printf("%s: %s %s\n", resp.Event.Type, string(resp.Event.Kv.Key), string(resp.Event.Kv.Value)) } }
func recvLoop(wStream pb.Watch_WatchClient) { for { resp, err := wStream.Recv() if err == io.EOF { os.Exit(0) } if err != nil { panic(err) } fmt.Printf("%s: %s %s\n", resp.Event.Type, string(resp.Event.Kv.Key), string(resp.Event.Kv.Value)) } }
// serveWatchClient forwards messages from the grpc stream to run() func (w *watchGrpcStream) serveWatchClient(wc pb.Watch_WatchClient) { for { resp, err := wc.Recv() if err != nil { select { case w.errc <- err: case <-w.donec: } return } select { case w.respc <- resp: case <-w.donec: return } } }
// WaitResponse waits on the given stream for given duration. // If there is no more events, true and a nil response will be // returned closing the WatchClient stream. Or the response will // be returned. func WaitResponse(wc pb.Watch_WatchClient, timeout time.Duration) (bool, *pb.WatchResponse) { rCh := make(chan *pb.WatchResponse) go func() { resp, _ := wc.Recv() rCh <- resp }() select { case nr := <-rCh: return false, nr case <-time.After(timeout): } wc.CloseSend() rv, ok := <-rCh if rv != nil || !ok { return false, rv } return true, nil }
// resumeWatchers rebuilds every registered watcher on a new client func (w *watchGrpcStream) resumeWatchers(wc pb.Watch_WatchClient) error { w.mu.RLock() streams := make([]*watcherStream, 0, len(w.streams)) for _, ws := range w.streams { streams = append(streams, ws) } w.mu.RUnlock() for _, ws := range streams { // drain recvc so no old WatchResponses (e.g., Created messages) // are processed while resuming ws.drain() // pause serveStream ws.resumec <- -1 // reconstruct watcher from initial request if ws.lastRev != 0 { ws.initReq.rev = ws.lastRev } if err := wc.Send(ws.initReq.toPB()); err != nil { return err } // wait for request ack resp, err := wc.Recv() if err != nil { return err } else if len(resp.Events) != 0 || !resp.Created { return fmt.Errorf("watcher: unexpected response (%+v)", resp) } // id may be different since new remote watcher; update map w.mu.Lock() delete(w.streams, ws.id) ws.id = resp.WatchId w.streams[ws.id] = ws w.mu.Unlock() // unpause serveStream ws.resumec <- ws.lastRev } return nil }
// waitResponse waits on the given stream for given duration. // If there is no more events, true and a nil response will be // returned closing the WatchClient stream. Or the response will // be returned. func waitResponse(wc pb.Watch_WatchClient, timeout time.Duration) (bool, *pb.WatchResponse) { rCh := make(chan *pb.WatchResponse, 1) donec := make(chan struct{}) defer close(donec) go func() { resp, _ := wc.Recv() select { case rCh <- resp: case <-donec: } }() select { case nr := <-rCh: return false, nr case <-time.After(timeout): } // didn't get response wc.CloseSend() return true, nil }
func recvLoop(wStream pb.Watch_WatchClient) { for { resp, err := wStream.Recv() if err == io.EOF { os.Exit(ExitSuccess) } if err != nil { ExitWithError(ExitError, err) } switch { // TODO: handle canceled/compacted and other control response types case resp.Created: fmt.Printf("watcher created: id %08x\n", resp.WatchId) case resp.Canceled: fmt.Printf("watcher canceled: id %08x\n", resp.WatchId) default: for _, ev := range resp.Events { fmt.Printf("%s: %s %s\n", ev.Type, string(ev.Kv.Key), string(ev.Kv.Value)) } } } }
// resumeWatchers rebuilds every registered watcher on a new client func (w *watcher) resumeWatchers(wc pb.Watch_WatchClient) error { streams := []*watcherStream{} w.mu.RLock() for _, ws := range w.streams { streams = append(streams, ws) } w.mu.RUnlock() for _, ws := range streams { // reconstruct watcher from initial request if ws.lastRev != 0 { ws.initReq.rev = ws.lastRev } if err := wc.Send(ws.initReq.toPB()); err != nil { return err } // wait for request ack resp, err := wc.Recv() if err != nil { return err } else if len(resp.Events) != 0 || resp.Created != true { return fmt.Errorf("watcher: unexpected response (%+v)", resp) } // id may be different since new remote watcher; update map w.mu.Lock() delete(w.streams, ws.id) ws.id = resp.WatchId w.streams[ws.id] = ws w.mu.Unlock() ws.resumec <- ws.lastRev } return nil }