Skip to content

GODRIVER-3255 Await heartbeat checks upto freq when polling #1720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 1, 2024
Merged
43 changes: 43 additions & 0 deletions mongo/integration/sdam_prose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"net"
"os"
"runtime"
"sync"
"sync/atomic"
"testing"
"time"

Expand Down Expand Up @@ -232,4 +234,45 @@ func TestServerHeartbeatStartedEvent(t *testing.T) {
}
assert.Equal(t, expectedEvents, actualEvents)
})

mt := mtest.New(t)

mt.Run("polling must await frequency", func(mt *mtest.T) {
var heartbeatStartedCount atomic.Int64

servers := map[string]bool{}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly certain there are no concurrency concerns here since this is a set (i.e. nothing is aggregated).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go maps are not concurrent safe except for read-only use, independent of the keys or data written. Here's the data race detector error:

WARNING: DATA RACE
Read at 0x00c000511470 by goroutine 122:
  go.mongodb.org/mongo-driver/mongo/integration.TestServerHeartbeatStartedEvent.func2()
      /mongo-go-driver/mongo/integration/sdam_prose_test.go:266 +0x370
  go.mongodb.org/mongo-driver/mongo/integration/mtest.(*T).Run.(*T).RunOpts.func1()
      /mongo-go-driver/mongo/integration/mtest/mongotest.go:267 +0x2ac
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x180
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1742 +0x40

Previous write at 0x00c000511470 by goroutine 195:
  runtime.mapaccess2_faststr()
      /usr/local/go/src/runtime/map_faststr.go:108 +0x42c
  go.mongodb.org/mongo-driver/mongo/integration.TestServerHeartbeatStartedEvent.func2.2()
      /mongo-go-driver/mongo/integration/sdam_prose_test.go:249 +0xb8
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).publishTopologyDescriptionChangedEvent()
      /mongo-go-driver/x/mongo/driver/topology/topology.go:1067 +0x224
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).apply()
      /mongo-go-driver/x/mongo/driver/topology/topology.go:973 +0xe98
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.New.func1()
      /mongo-go-driver/x/mongo/driver/topology/topology.go:163 +0x78
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).updateDescription()
      /mongo-go-driver/x/mongo/driver/topology/server.go:707 +0x140
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).update.func3()
      /mongo-go-driver/x/mongo/driver/topology/server.go:624 +0xd8
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).update()
      /mongo-go-driver/x/mongo/driver/topology/server.go:654 +0x4f0
  go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).Connect.gowrap1()
      /mongo-go-driver/x/mongo/driver/topology/server.go:252 +0x34

Copy link
Member Author

@prestonvasquez prestonvasquez Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of this test it seems like it shouldn't matter. We're just checking that the number of heartbeats doesn't get ahead of discovery, AFAIK the size of the set doesn't have to be precise at the time we make the assertion. Anyway, updated with a mutex.

Copy link
Member Author

@prestonvasquez prestonvasquez Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though there is a race concern I don't think you can actually break what is being tested. I wasn't sure the race detector would care in this case 🤷

serversMu := sync.RWMutex{} // Guard the servers set

serverMonitor := &event.ServerMonitor{
ServerHeartbeatStarted: func(*event.ServerHeartbeatStartedEvent) {
heartbeatStartedCount.Add(1)
},
TopologyDescriptionChanged: func(evt *event.TopologyDescriptionChangedEvent) {
serversMu.Lock()
defer serversMu.Unlock()

for _, srv := range evt.NewDescription.Servers {
servers[srv.Addr.String()] = true
}
},
}

// Create a client with heartbeatFrequency=100ms,
// serverMonitoringMode=poll. Use SDAM to record the number of times the
// a heartbeat is started and the number of servers discovered.
mt.ResetClient(options.Client().
SetServerMonitor(serverMonitor).
SetServerMonitoringMode(options.ServerMonitoringModePoll))

// Per specifications, minHeartbeatFrequencyMS=500ms. So, within the first
// 500ms the heartbeatStartedCount should be LEQ to the number of discovered
// servers.
time.Sleep(500 * time.Millisecond)

serversMu.Lock()
serverCount := int64(len(servers))
serversMu.Unlock()

assert.LessOrEqual(mt, heartbeatStartedCount.Load(), serverCount)
})
}
2 changes: 1 addition & 1 deletion x/mongo/driver/topology/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ func (s *Server) update() {
s.monitorOnce.Do(s.rttMonitor.connect)
}

if isStreamable(s) || connectionIsStreaming || transitionedFromNetworkError {
if isStreamingEnabled(s) && (isStreamable(s) || connectionIsStreaming) || transitionedFromNetworkError {
continue
}

Expand Down
Loading