diff --git a/Dockerfile b/Dockerfile index 446ab1d5f2..077967d039 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ tzdata \ gpg \ apt-utils \ + libc6-dev \ + gcc \ make && \ apt-add-repository ppa:longsleep/golang-backports && \ apt-get -qq update && \ diff --git a/x/mongo/driver/topology/rtt_monitor.go b/x/mongo/driver/topology/rtt_monitor.go index e3e2e04683..7308c88f15 100644 --- a/x/mongo/driver/topology/rtt_monitor.go +++ b/x/mongo/driver/topology/rtt_monitor.go @@ -39,7 +39,12 @@ type rttConfig struct { } type rttMonitor struct { - mu sync.RWMutex // mu guards samples, offset, minRTT, averageRTT, and averageRTTSet + mu sync.RWMutex // mu guards samples, offset, minRTT, averageRTT, and averageRTTSet + + // connMu guards connecting and disconnecting. This is necessary since + // disconnecting will await the cancelation of a started connection. The + // use case for rttMonitor.connect needs to be goroutine safe. + connMu sync.Mutex samples []time.Duration offset int minRTT time.Duration @@ -52,6 +57,7 @@ type rttMonitor struct { ctx context.Context cancelFn context.CancelFunc started bool + done chan struct{} } var _ driver.RTTMonitor = &rttMonitor{} @@ -75,20 +81,34 @@ func newRTTMonitor(cfg *rttConfig) *rttMonitor { } func (r *rttMonitor) connect() { - r.closeWg.Add(1) + r.connMu.Lock() + defer r.connMu.Unlock() + r.started = true - go r.start() + r.closeWg.Add(1) + + go func() { + defer r.closeWg.Done() + + r.start() + }() } func (r *rttMonitor) disconnect() { - // Signal for the routine to stop. + r.connMu.Lock() + defer r.connMu.Unlock() + + if !r.started { + return + } + r.cancelFn() + + // Wait for the existing connection to complete. r.closeWg.Wait() } func (r *rttMonitor) start() { - defer r.closeWg.Done() - var conn *connection defer func() { if conn != nil {