-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Collection Management, Index Management, Reactive Streams
-
None
-
None
-
Java Drivers
-
None
-
None
-
None
-
None
-
None
-
None
Spec requirements
The Server Selection spec classifies listCollections as "should-use-primary": 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".
The Enumerate Databases spec carries an equivalent requirement for listDatabases: "Drivers MUST run the listDatabases command only on the primary node in replica set topology".
No specification explicitly covers listIndexes in relation to read preference, but the behavior is implied in the server-selection spec to be equivalent to listCollections.
Behavior
The sync driver ignores the configured read preference for these commands and always selects the primary. The reactive streams driver honors it: with a secondary read preference on the client or database, it selects a secondary and sends the read preference in the command.
Verified against a two-node replica set (primary on 27017, secondary on 27018), observing the listCollections commandStartedEvent:
SYNC listCollections -> server=localhost:27017 $readPreference=null
REACTIVE listCollections -> server=localhost:27018 $readPreference={"mode": "secondary"}
(same result for all three operations in both variants)
Reproducer
Against a replica set with at least one secondary:
public class Reproducer { public static void main(final String[] args) throws Exception { CountDownLatch latch = new CountDownLatch(1); MongoClientSettings settings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString("mongodb://localhost:27017,localhost:27018/?replicaSet=rs0")) .readPreference(ReadPreference.secondary()) .addCommandListener(new CommandListener() { @Override public void commandStarted(final CommandStartedEvent event) { if (event.getCommandName().equals("listCollections")) { System.out.println(event.getConnectionDescription().getServerAddress() + " $readPreference=" + event.getCommand().get("$readPreference")); } } }) .build(); try (MongoClient client = MongoClients.create(settings)) { client.getDatabase("admin").listCollections().subscribe(new Subscriber<BsonDocument>() { @Override public void onSubscribe(final Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(final BsonDocument t) { } @Override public void onError(final Throwable t) { t.printStackTrace(); latch.countDown(); } @Override public void onComplete() { latch.countDown(); } }); latch.await(); } } }
Output with the reactive streams client (swap in com.mongodb.client.MongoClients for the sync comparison):
localhost:27018 $readPreference={"mode": "secondary"}
Specification and test coverage
There are currently no specification-defined tests of this requirement. The server-selection JSON tests only exercise the selection algorithm, and no unified test file combines a list* operation with a read preference assertion. Nothing driver-local covers it either.
A unified-format regression test is feasible without format changes: assert that $readPreference does not exist on the listCollections commandStartedEvent when the entity is configured with secondary. There is precedent in run-command/tests/unified/runCommand.yml, which asserts exactly this for runCommand.
Related
- DRIVERS-1186 proposes relaxing the spec so these commands respect read preference. If that change is adopted, the fix direction reverses (the sync driver should stop forcing primary instead). This ticket tracks compliance with the current spec.
- related to
-
DRIVERS-1186 Allow database/collection/index enumeration to respect read preference
-
- Needs Triage
-