From 490499267b352c15028bd7cc73aefd26aca2db2a Mon Sep 17 00:00:00 2001 From: Mark Rushakoff Date: Tue, 19 Mar 2019 15:14:58 -0700 Subject: [PATCH] fix(query): allow multiple calls to Release proxy bridge iterator The asyncStatsResultIterator used inside QueryServiceProxyBridge assumed that Release would only be called once. The godoc for ResultIterator specifies that it is safe to call Release multiple times. Now, you can do that without causing Release to block indefinitely. --- query/bridges.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/query/bridges.go b/query/bridges.go index 2aa7c2059fb..ba78423a501 100644 --- a/query/bridges.go +++ b/query/bridges.go @@ -36,34 +36,38 @@ func (b QueryServiceProxyBridge) Query(ctx context.Context, req *Request) (flux. } r, w := io.Pipe() - statsChan := make(chan flux.Statistics, 1) + asri := &asyncStatsResultIterator{statsReady: make(chan struct{})} go func() { stats, err := b.ProxyQueryService.Query(ctx, w, preq) _ = w.CloseWithError(err) - statsChan <- stats + asri.stats = stats + close(asri.statsReady) }() dec := csv.NewMultiResultDecoder(csv.ResultDecoderConfig{}) ri, err := dec.Decode(r) - return asyncStatsResultIterator{ - ResultIterator: ri, - statsChan: statsChan, - }, err + asri.ResultIterator = ri + return asri, err } type asyncStatsResultIterator struct { flux.ResultIterator - statsChan chan flux.Statistics - stats flux.Statistics + + // Channel that is closed when stats have been written. + statsReady chan struct{} + + // Statistics gathered from calling the proxy query service. + // This field must not be read until statsReady is closed. + stats flux.Statistics } -func (i asyncStatsResultIterator) Release() { +func (i *asyncStatsResultIterator) Release() { i.ResultIterator.Release() - i.stats = <-i.statsChan } -func (i asyncStatsResultIterator) Statistics() flux.Statistics { +func (i *asyncStatsResultIterator) Statistics() flux.Statistics { + <-i.statsReady return i.stats }