Skip to content

Commit 189f7a7

Browse files
author
Divjot Arora
committed
GODRIVER-1713 Pass read preference to operations layer for RunCommand (#487)
1 parent 8376d6d commit 189f7a7

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

mongo/database.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,12 @@ func (db *Database) processRunCommand(ctx context.Context, cmd interface{},
168168
return operation.NewCommand(runCmdDoc).
169169
Session(sess).CommandMonitor(db.client.monitor).
170170
ServerSelector(readSelect).ClusterClock(db.client.clock).
171-
Database(db.name).Deployment(db.client.deployment).ReadConcern(db.readConcern).Crypt(db.client.crypt), sess, nil
171+
Database(db.name).Deployment(db.client.deployment).ReadConcern(db.readConcern).
172+
Crypt(db.client.crypt).ReadPreference(ro.ReadPreference), sess, nil
172173
}
173174

174-
// RunCommand executes the given command against the database.
175+
// RunCommand executes the given command against the database. This function does not obey the Database's read
176+
// preference. To specify a read preference, the RunCmdOptions.ReadPreference option must be used.
175177
//
176178
// The runCommand parameter must be a document for the command to be executed. It cannot be nil.
177179
// This must be an order-preserving type such as bson.D. Map types such as bson.M are not valid.
@@ -198,8 +200,9 @@ func (db *Database) RunCommand(ctx context.Context, runCommand interface{}, opts
198200
}
199201

200202
// RunCommandCursor executes the given command against the database and parses the response as a cursor. If the command
201-
// being executed does not return a cursor (e.g. insert), the command will be executed on the server and an error
202-
// will be returned because the server response cannot be parsed as a cursor.
203+
// being executed does not return a cursor (e.g. insert), the command will be executed on the server and an error will
204+
// be returned because the server response cannot be parsed as a cursor. This function does not obey the Database's read
205+
// preference. To specify a read preference, the RunCmdOptions.ReadPreference option must be used.
203206
//
204207
// The runCommand parameter must be a document for the command to be executed. It cannot be nil.
205208
// This must be an order-preserving type such as bson.D. Map types such as bson.M are not valid.

mongo/integration/database_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"go.mongodb.org/mongo-driver/mongo"
1919
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
2020
"go.mongodb.org/mongo-driver/mongo/options"
21+
"go.mongodb.org/mongo-driver/mongo/readpref"
22+
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
2123
)
2224

2325
const (
@@ -60,6 +62,32 @@ func TestDatabase(t *testing.T) {
6062
assert.Equal(mt, true, result.IsMaster, "expected isMaster value true, got false")
6163
assert.Equal(mt, 1.0, result.Ok, "expected ok value 1.0, got %v", result.Ok)
6264
})
65+
66+
// We set min server version 3.6 because pre-3.6 servers use OP_QUERY, so the command document will look like
67+
// {$query: {...}, $readPreference: {...}}. Per the command monitoring spec, the $query subdocument is unwrapped
68+
// and the $readPreference is dropped for monitoring purposes, so we can't examine it.
69+
readPrefOpts := mtest.NewOptions().
70+
Topologies(mtest.Sharded).
71+
MinServerVersion("3.6")
72+
mt.RunOpts("read pref passed to mongos", readPrefOpts, func(mt *mtest.T) {
73+
// When communicating with a mongos, the supplied read preference should be passed down to the operations
74+
// layer, which should add a top-level $readPreference field to the command.
75+
76+
runCmdOpts := options.RunCmd().
77+
SetReadPreference(readpref.SecondaryPreferred())
78+
err := mt.DB.RunCommand(mtest.Background, bson.D{{"isMaster", 1}}, runCmdOpts).Err()
79+
assert.Nil(mt, err, "RunCommand error: %v", err)
80+
81+
expected := bson.Raw(bsoncore.BuildDocumentFromElements(
82+
nil,
83+
bsoncore.AppendStringElement(nil, "mode", "secondaryPreferred"),
84+
))
85+
evt := mt.GetStartedEvent()
86+
assert.Equal(mt, "isMaster", evt.CommandName, "expected 'isMaster' command to be sent, got %q", evt.CommandName)
87+
actual, ok := evt.Command.Lookup("$readPreference").DocumentOK()
88+
assert.True(mt, ok, "expected command %v to contain a $readPreference document", evt.Command)
89+
assert.Equal(mt, expected, actual, "expected $readPreference document %v, got %v", expected, actual)
90+
})
6391
})
6492

6593
dropOpts := mtest.NewOptions().DatabaseName("dropDb")

0 commit comments

Comments
 (0)