[JAVA-2081] MongoClient does not respect ReadPreference Created: 12/Jan/16  Updated: 13/Jan/16  Resolved: 13/Jan/16

Status: Closed
Project: Java Driver
Component/s: Command Operations
Affects Version/s: 3.0.0
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Kay Agahd Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux 64 Bit


Issue Links:
Duplicate
duplicates JAVA-1767 listCollections helper fails with dir... Closed

 Description   

In the API doc is stated:

By default, all read and write operations will be made on the primary, but it's possible to read from secondaries by changing the read preference:
mongoClient.setReadPreference(ReadPreference.secondaryPreferred());


However, this seems not to apply at least to the follwing methods because they are overriding the actual set ReadPreference by "ReadPreference.primary()":

  • listDatabases()
  • listDatabaseNames()
  • getDatabase(dbName).listCollections()

This is very annoying because we want explicitly get this info from a secondary.



 Comments   
Comment by Kay Agahd [ 13/Jan/16 ]

Great, I confirm that v3.0.1 fixes the bug! So the API doc I've cited is correct too. Thank you!

Comment by Jeffrey Yemin [ 12/Jan/16 ]

I neglected to look at the Affects Version field. Now that I see you're on 3.0.0, I suspect you're just hitting JAVA-1767, which was fixed in 3.0.1.

Comment by Kay Agahd [ 12/Jan/16 ]

the supported way to use command helpers like these against a secondary is to connect directly to the secondary

We are connecting directly to one secondary (of a replset consisting of 3 members) by calling:

new MongoClient(new ServerAddress("<secondary-host-name>"), credentialList, options)

The options contain "readPreference(ReadPreference.secondaryPreferred())".
However, the execution of the above mentioned commands fails:

com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}. Client view of cluster state is {type=REPLICA_SET, servers=[{address=mongo-018.ipx:27017, type=REPLICA_SET_SECONDARY, roundTripTime=8,3 ms, state=CONNECTED}]
	at com.mongodb.connection.BaseCluster.createTimeoutException(BaseCluster.java:370) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.BaseCluster.selectServer(BaseCluster.java:101) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.<init>(ClusterBinding.java:75) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.<init>(ClusterBinding.java:71) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.binding.ClusterBinding.getReadConnectionSource(ClusterBinding.java:63) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:166) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.ListCollectionsOperation.execute(ListCollectionsOperation.java:172) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.ListCollectionsOperation.execute(ListCollectionsOperation.java:80) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.Mongo.execute(Mongo.java:736) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.Mongo$2.execute(Mongo.java:723) ~[mongo-java-driver-3.0.0.jar:na]


The reason we want to use a secondary is that we analyze the db schema from time to time to see any degradation of the schema, i.e. if fields are always using the same type, how big they are, how often they occur etc. Since this a very time and resource consuming task we prefer to let it run on a secondary.
One of the first commands to achieve this goal is to list all databases and collections. If these two commands require a primary we would need to put (also) the primary in the connection string, which want to avoid in order to be 100% sure that the primary is not being queried or stressed.

It seems that this issue had already been fixed in v2.13.2 but it revived in v3.0.
https://jira.mongodb.org/browse/JAVA-1842

Clients MUST NOT raise an exception if the topology type is Single.

Who is the client? The driver or the user of the driver?

There is definitely room to improve the documentation of command helpers for read operations to indicate that they don't respect read preference

Are you saying that the driver code is ok but only the doc is wrong? If so, why did you say that:

the supported way to use command helpers like these against a secondary is to connect directly to the secondary

Comment by Jeffrey Yemin [ 12/Jan/16 ]

The Java driver is implementing the server selection specification for use of read preference with commands, which states:

"should-use-primary": these commands are intended to be run on a primary, but would succeed – albeit with possibly stale data – when run against a secondary. An example is listCollections.

These command-specific helpers MUST use a read preference mode of 'primary', MUST NOT take a read preference argument and MUST ignore any default read preference from client, database or collection configuration. Languages with dynamic argument lists MUST throw an error if a read preference is provided as an argument.

Clients MUST NOT raise an exception if the topology type is Single.

As indicated by the last paragraph quoted above, the supported way to use command helpers like these against a secondary is to connect directly to the secondary, e.g.

new MongoClient(new ServerAddress("<secondary-host-name>"))
new MongoClient(new MongoClientURI("mongodb://<secondary-host-name>"))

There is definitely room to improve the documentation of command helpers for read operations to indicate that they don't respect read preference, so thank you for pointing that out.

I'd also like to know why you explicitly want to execute these operations against a secondary. Can you let me know?

Regards,
Jeff

Generated at Thu Feb 08 08:56:16 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.