3131from pymongo .server_type import SERVER_TYPE
3232
3333
34+ def _validate_max_staleness (max_staleness ,
35+ heartbeat_frequency ,
36+ idle_write_period ):
37+ if max_staleness < heartbeat_frequency + idle_write_period :
38+ raise ConfigurationError (
39+ "maxStalenessSeconds must be at least heartbeatFrequencyMS +"
40+ " %d seconds. maxStalenessSeconds is set to %d,"
41+ " heartbeatFrequencyMS is set to %d." % (
42+ idle_write_period , max_staleness ,
43+ heartbeat_frequency * 1000 ))
44+
45+
3446def _with_primary (max_staleness , selection ):
3547 """Apply max_staleness, in seconds, to a Selection with a known primary."""
3648 primary = selection .primary
49+ assert primary
50+
51+ # Server Selection Spec: If the TopologyType is ReplicaSetWithPrimary, a
52+ # client MUST raise an error if maxStaleness < heartbeatFrequency +
53+ # (primary's idleWritePeriod).
54+ _validate_max_staleness (max_staleness ,
55+ selection .heartbeat_frequency ,
56+ primary .idle_write_period )
57+
3758 sds = []
3859
3960 for s in selection .server_descriptions :
@@ -54,9 +75,25 @@ def _with_primary(max_staleness, selection):
5475
5576def _no_primary (max_staleness , selection ):
5677 """Apply max_staleness, in seconds, to a Selection with no known primary."""
78+ # Secondary that's replicated the most recent writes.
5779 smax = selection .secondary_with_max_last_write_date ()
80+ if not smax :
81+ # No secondaries and no primary, short-circuit out of here.
82+ return selection .with_server_descriptions ([])
83+
84+ # Secondary we've most recently checked.
85+ srecent = selection .secondary_with_max_last_update_time ()
86+ assert srecent
87+
5888 sds = []
5989
90+ # Server Selection Spec: If the TopologyType is ReplicaSetNoPrimary, a
91+ # client MUST raise an error if maxStaleness < heartbeatFrequency +
92+ # (idleWritePeriod of secondary with greatest lastUpdateTime).
93+ _validate_max_staleness (max_staleness ,
94+ selection .heartbeat_frequency ,
95+ srecent .idle_write_period )
96+
6097 for s in selection .server_descriptions :
6198 if s .server_type == SERVER_TYPE .RSSecondary :
6299 # See max-staleness.rst for explanation of this formula.
@@ -77,13 +114,6 @@ def select(max_staleness, selection):
77114 if not max_staleness :
78115 return selection
79116
80- # Server Selection Spec: "A driver MUST raise an error if the
81- # TopologyType is ReplicaSetWithPrimary or ReplicaSetNoPrimary and
82- # maxStalenessSeconds * 1000 is less than twice heartbeatFrequencyMS."
83- if max_staleness < 2 * selection .heartbeat_frequency :
84- raise ConfigurationError (
85- "maxStalenessSeconds must be twice heartbeatFrequencyMS" )
86-
87117 if selection .primary :
88118 return _with_primary (max_staleness , selection )
89119 else :
0 commit comments