sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,609 @@
1
+ # Copyright 2012-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License",
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Utilities for choosing which member of a replica set to read from."""
16
+
17
+ from collections import abc
18
+ from typing import Any, Dict, Mapping, Optional, Sequence
19
+
20
+ from pymongo import max_staleness_selectors
21
+ from pymongo.errors import ConfigurationError
22
+ from pymongo.server_selectors import (
23
+ member_with_tags_server_selector,
24
+ secondary_with_tags_server_selector,
25
+ )
26
+
27
+ _PRIMARY = 0
28
+ _PRIMARY_PREFERRED = 1
29
+ _SECONDARY = 2
30
+ _SECONDARY_PREFERRED = 3
31
+ _NEAREST = 4
32
+
33
+
34
+ _MONGOS_MODES = (
35
+ "primary",
36
+ "primaryPreferred",
37
+ "secondary",
38
+ "secondaryPreferred",
39
+ "nearest",
40
+ )
41
+
42
+
43
+ def _validate_tag_sets(tag_sets):
44
+ """Validate tag sets for a MongoClient."""
45
+ if tag_sets is None:
46
+ return tag_sets
47
+
48
+ if not isinstance(tag_sets, (list, tuple)):
49
+ raise TypeError(("Tag sets %r invalid, must be a sequence") % (tag_sets,))
50
+ if len(tag_sets) == 0:
51
+ raise ValueError(
52
+ ("Tag sets %r invalid, must be None or contain at least one set of tags") % (tag_sets,)
53
+ )
54
+
55
+ for tags in tag_sets:
56
+ if not isinstance(tags, abc.Mapping):
57
+ raise TypeError(
58
+ "Tag set %r invalid, must be an instance of dict, "
59
+ "bson.son.SON or other type that inherits from "
60
+ "collection.Mapping" % (tags,)
61
+ )
62
+
63
+ return list(tag_sets)
64
+
65
+
66
+ def _invalid_max_staleness_msg(max_staleness):
67
+ return "maxStalenessSeconds must be a positive integer, not %s" % max_staleness
68
+
69
+
70
+ # Some duplication with common.py to avoid import cycle.
71
+ def _validate_max_staleness(max_staleness):
72
+ """Validate max_staleness."""
73
+ if max_staleness == -1:
74
+ return -1
75
+
76
+ if not isinstance(max_staleness, int):
77
+ raise TypeError(_invalid_max_staleness_msg(max_staleness))
78
+
79
+ if max_staleness <= 0:
80
+ raise ValueError(_invalid_max_staleness_msg(max_staleness))
81
+
82
+ return max_staleness
83
+
84
+
85
+ def _validate_hedge(hedge):
86
+ """Validate hedge."""
87
+ if hedge is None:
88
+ return None
89
+
90
+ if not isinstance(hedge, dict):
91
+ raise TypeError("hedge must be a dictionary, not %r" % (hedge,))
92
+
93
+ return hedge
94
+
95
+
96
+ _Hedge = Mapping[str, Any]
97
+ _TagSets = Sequence[Mapping[str, Any]]
98
+
99
+
100
+ class _ServerMode(object):
101
+ """Base class for all read preferences."""
102
+
103
+ __slots__ = ("__mongos_mode", "__mode", "__tag_sets", "__max_staleness", "__hedge")
104
+
105
+ def __init__(
106
+ self,
107
+ mode: int,
108
+ tag_sets: Optional[_TagSets] = None,
109
+ max_staleness: int = -1,
110
+ hedge: Optional[_Hedge] = None,
111
+ ) -> None:
112
+ self.__mongos_mode = _MONGOS_MODES[mode]
113
+ self.__mode = mode
114
+ self.__tag_sets = _validate_tag_sets(tag_sets)
115
+ self.__max_staleness = _validate_max_staleness(max_staleness)
116
+ self.__hedge = _validate_hedge(hedge)
117
+
118
+ @property
119
+ def name(self) -> str:
120
+ """The name of this read preference."""
121
+ return self.__class__.__name__
122
+
123
+ @property
124
+ def mongos_mode(self) -> str:
125
+ """The mongos mode of this read preference."""
126
+ return self.__mongos_mode
127
+
128
+ @property
129
+ def document(self) -> Dict[str, Any]:
130
+ """Read preference as a document."""
131
+ doc: Dict[str, Any] = {"mode": self.__mongos_mode}
132
+ if self.__tag_sets not in (None, [{}]):
133
+ doc["tags"] = self.__tag_sets
134
+ if self.__max_staleness != -1:
135
+ doc["maxStalenessSeconds"] = self.__max_staleness
136
+ if self.__hedge not in (None, {}):
137
+ doc["hedge"] = self.__hedge
138
+ return doc
139
+
140
+ @property
141
+ def mode(self) -> int:
142
+ """The mode of this read preference instance."""
143
+ return self.__mode
144
+
145
+ @property
146
+ def tag_sets(self) -> _TagSets:
147
+ """Set ``tag_sets`` to a list of dictionaries like [{'dc': 'ny'}] to
148
+ read only from members whose ``dc`` tag has the value ``"ny"``.
149
+ To specify a priority-order for tag sets, provide a list of
150
+ tag sets: ``[{'dc': 'ny'}, {'dc': 'la'}, {}]``. A final, empty tag
151
+ set, ``{}``, means "read from any member that matches the mode,
152
+ ignoring tags." MongoClient tries each set of tags in turn
153
+ until it finds a set of tags with at least one matching member.
154
+
155
+ .. seealso:: `Data-Center Awareness
156
+ <https://www.mongodb.com/docs/manual/data-center-awareness/>`_
157
+ """
158
+ return list(self.__tag_sets) if self.__tag_sets else [{}]
159
+
160
+ @property
161
+ def max_staleness(self) -> int:
162
+ """The maximum estimated length of time (in seconds) a replica set
163
+ secondary can fall behind the primary in replication before it will
164
+ no longer be selected for operations, or -1 for no maximum."""
165
+ return self.__max_staleness
166
+
167
+ @property
168
+ def hedge(self) -> Optional[_Hedge]:
169
+ """The read preference ``hedge`` parameter.
170
+
171
+ A dictionary that configures how the server will perform hedged reads.
172
+ It consists of the following keys:
173
+
174
+ - ``enabled``: Enables or disables hedged reads in sharded clusters.
175
+
176
+ Hedged reads are automatically enabled in MongoDB 4.4+ when using a
177
+ ``nearest`` read preference. To explicitly enable hedged reads, set
178
+ the ``enabled`` key to ``true``::
179
+
180
+ >>> Nearest(hedge={'enabled': True})
181
+
182
+ To explicitly disable hedged reads, set the ``enabled`` key to
183
+ ``False``::
184
+
185
+ >>> Nearest(hedge={'enabled': False})
186
+
187
+ .. versionadded:: 3.11
188
+ """
189
+ return self.__hedge
190
+
191
+ @property
192
+ def min_wire_version(self) -> int:
193
+ """The wire protocol version the server must support.
194
+
195
+ Some read preferences impose version requirements on all servers (e.g.
196
+ maxStalenessSeconds requires MongoDB 3.4 / maxWireVersion 5).
197
+
198
+ All servers' maxWireVersion must be at least this read preference's
199
+ `min_wire_version`, or the driver raises
200
+ :exc:`~pymongo.errors.ConfigurationError`.
201
+ """
202
+ return 0 if self.__max_staleness == -1 else 5
203
+
204
+ def __repr__(self):
205
+ return "%s(tag_sets=%r, max_staleness=%r, hedge=%r)" % (
206
+ self.name,
207
+ self.__tag_sets,
208
+ self.__max_staleness,
209
+ self.__hedge,
210
+ )
211
+
212
+ def __eq__(self, other: Any) -> bool:
213
+ if isinstance(other, _ServerMode):
214
+ return (
215
+ self.mode == other.mode
216
+ and self.tag_sets == other.tag_sets
217
+ and self.max_staleness == other.max_staleness
218
+ and self.hedge == other.hedge
219
+ )
220
+ return NotImplemented
221
+
222
+ def __ne__(self, other: Any) -> bool:
223
+ return not self == other
224
+
225
+ def __getstate__(self):
226
+ """Return value of object for pickling.
227
+
228
+ Needed explicitly because __slots__() defined.
229
+ """
230
+ return {
231
+ "mode": self.__mode,
232
+ "tag_sets": self.__tag_sets,
233
+ "max_staleness": self.__max_staleness,
234
+ "hedge": self.__hedge,
235
+ }
236
+
237
+ def __setstate__(self, value):
238
+ """Restore from pickling."""
239
+ self.__mode = value["mode"]
240
+ self.__mongos_mode = _MONGOS_MODES[self.__mode]
241
+ self.__tag_sets = _validate_tag_sets(value["tag_sets"])
242
+ self.__max_staleness = _validate_max_staleness(value["max_staleness"])
243
+ self.__hedge = _validate_hedge(value["hedge"])
244
+
245
+
246
+ class Primary(_ServerMode):
247
+ """Primary read preference.
248
+
249
+ * When directly connected to one mongod queries are allowed if the server
250
+ is standalone or a replica set primary.
251
+ * When connected to a mongos queries are sent to the primary of a shard.
252
+ * When connected to a replica set queries are sent to the primary of
253
+ the replica set.
254
+ """
255
+
256
+ __slots__ = ()
257
+
258
+ def __init__(self) -> None:
259
+ super(Primary, self).__init__(_PRIMARY)
260
+
261
+ def __call__(self, selection: Any) -> Any:
262
+ """Apply this read preference to a Selection."""
263
+ return selection.primary_selection
264
+
265
+ def __repr__(self):
266
+ return "Primary()"
267
+
268
+ def __eq__(self, other: Any) -> bool:
269
+ if isinstance(other, _ServerMode):
270
+ return other.mode == _PRIMARY
271
+ return NotImplemented
272
+
273
+
274
+ class PrimaryPreferred(_ServerMode):
275
+ """PrimaryPreferred read preference.
276
+
277
+ * When directly connected to one mongod queries are allowed to standalone
278
+ servers, to a replica set primary, or to replica set secondaries.
279
+ * When connected to a mongos queries are sent to the primary of a shard if
280
+ available, otherwise a shard secondary.
281
+ * When connected to a replica set queries are sent to the primary if
282
+ available, otherwise a secondary.
283
+
284
+ .. note:: When a :class:`~pymongo.mongo_client.MongoClient` is first
285
+ created reads will be routed to an available secondary until the
286
+ primary of the replica set is discovered.
287
+
288
+ :Parameters:
289
+ - `tag_sets`: The :attr:`~tag_sets` to use if the primary is not
290
+ available.
291
+ - `max_staleness`: (integer, in seconds) The maximum estimated
292
+ length of time a replica set secondary can fall behind the primary in
293
+ replication before it will no longer be selected for operations.
294
+ Default -1, meaning no maximum. If it is set, it must be at least
295
+ 90 seconds.
296
+ - `hedge`: The :attr:`~hedge` to use if the primary is not available.
297
+
298
+ .. versionchanged:: 3.11
299
+ Added ``hedge`` parameter.
300
+ """
301
+
302
+ __slots__ = ()
303
+
304
+ def __init__(
305
+ self,
306
+ tag_sets: Optional[_TagSets] = None,
307
+ max_staleness: int = -1,
308
+ hedge: Optional[_Hedge] = None,
309
+ ) -> None:
310
+ super(PrimaryPreferred, self).__init__(_PRIMARY_PREFERRED, tag_sets, max_staleness, hedge)
311
+
312
+ def __call__(self, selection: Any) -> Any:
313
+ """Apply this read preference to Selection."""
314
+ if selection.primary:
315
+ return selection.primary_selection
316
+ else:
317
+ return secondary_with_tags_server_selector(
318
+ self.tag_sets, max_staleness_selectors.select(self.max_staleness, selection)
319
+ )
320
+
321
+
322
+ class Secondary(_ServerMode):
323
+ """Secondary read preference.
324
+
325
+ * When directly connected to one mongod queries are allowed to standalone
326
+ servers, to a replica set primary, or to replica set secondaries.
327
+ * When connected to a mongos queries are distributed among shard
328
+ secondaries. An error is raised if no secondaries are available.
329
+ * When connected to a replica set queries are distributed among
330
+ secondaries. An error is raised if no secondaries are available.
331
+
332
+ :Parameters:
333
+ - `tag_sets`: The :attr:`~tag_sets` for this read preference.
334
+ - `max_staleness`: (integer, in seconds) The maximum estimated
335
+ length of time a replica set secondary can fall behind the primary in
336
+ replication before it will no longer be selected for operations.
337
+ Default -1, meaning no maximum. If it is set, it must be at least
338
+ 90 seconds.
339
+ - `hedge`: The :attr:`~hedge` for this read preference.
340
+
341
+ .. versionchanged:: 3.11
342
+ Added ``hedge`` parameter.
343
+ """
344
+
345
+ __slots__ = ()
346
+
347
+ def __init__(
348
+ self,
349
+ tag_sets: Optional[_TagSets] = None,
350
+ max_staleness: int = -1,
351
+ hedge: Optional[_Hedge] = None,
352
+ ) -> None:
353
+ super(Secondary, self).__init__(_SECONDARY, tag_sets, max_staleness, hedge)
354
+
355
+ def __call__(self, selection: Any) -> Any:
356
+ """Apply this read preference to Selection."""
357
+ return secondary_with_tags_server_selector(
358
+ self.tag_sets, max_staleness_selectors.select(self.max_staleness, selection)
359
+ )
360
+
361
+
362
+ class SecondaryPreferred(_ServerMode):
363
+ """SecondaryPreferred read preference.
364
+
365
+ * When directly connected to one mongod queries are allowed to standalone
366
+ servers, to a replica set primary, or to replica set secondaries.
367
+ * When connected to a mongos queries are distributed among shard
368
+ secondaries, or the shard primary if no secondary is available.
369
+ * When connected to a replica set queries are distributed among
370
+ secondaries, or the primary if no secondary is available.
371
+
372
+ .. note:: When a :class:`~pymongo.mongo_client.MongoClient` is first
373
+ created reads will be routed to the primary of the replica set until
374
+ an available secondary is discovered.
375
+
376
+ :Parameters:
377
+ - `tag_sets`: The :attr:`~tag_sets` for this read preference.
378
+ - `max_staleness`: (integer, in seconds) The maximum estimated
379
+ length of time a replica set secondary can fall behind the primary in
380
+ replication before it will no longer be selected for operations.
381
+ Default -1, meaning no maximum. If it is set, it must be at least
382
+ 90 seconds.
383
+ - `hedge`: The :attr:`~hedge` for this read preference.
384
+
385
+ .. versionchanged:: 3.11
386
+ Added ``hedge`` parameter.
387
+ """
388
+
389
+ __slots__ = ()
390
+
391
+ def __init__(
392
+ self,
393
+ tag_sets: Optional[_TagSets] = None,
394
+ max_staleness: int = -1,
395
+ hedge: Optional[_Hedge] = None,
396
+ ) -> None:
397
+ super(SecondaryPreferred, self).__init__(
398
+ _SECONDARY_PREFERRED, tag_sets, max_staleness, hedge
399
+ )
400
+
401
+ def __call__(self, selection: Any) -> Any:
402
+ """Apply this read preference to Selection."""
403
+ secondaries = secondary_with_tags_server_selector(
404
+ self.tag_sets, max_staleness_selectors.select(self.max_staleness, selection)
405
+ )
406
+
407
+ if secondaries:
408
+ return secondaries
409
+ else:
410
+ return selection.primary_selection
411
+
412
+
413
+ class Nearest(_ServerMode):
414
+ """Nearest read preference.
415
+
416
+ * When directly connected to one mongod queries are allowed to standalone
417
+ servers, to a replica set primary, or to replica set secondaries.
418
+ * When connected to a mongos queries are distributed among all members of
419
+ a shard.
420
+ * When connected to a replica set queries are distributed among all
421
+ members.
422
+
423
+ :Parameters:
424
+ - `tag_sets`: The :attr:`~tag_sets` for this read preference.
425
+ - `max_staleness`: (integer, in seconds) The maximum estimated
426
+ length of time a replica set secondary can fall behind the primary in
427
+ replication before it will no longer be selected for operations.
428
+ Default -1, meaning no maximum. If it is set, it must be at least
429
+ 90 seconds.
430
+ - `hedge`: The :attr:`~hedge` for this read preference.
431
+
432
+ .. versionchanged:: 3.11
433
+ Added ``hedge`` parameter.
434
+ """
435
+
436
+ __slots__ = ()
437
+
438
+ def __init__(
439
+ self,
440
+ tag_sets: Optional[_TagSets] = None,
441
+ max_staleness: int = -1,
442
+ hedge: Optional[_Hedge] = None,
443
+ ) -> None:
444
+ super(Nearest, self).__init__(_NEAREST, tag_sets, max_staleness, hedge)
445
+
446
+ def __call__(self, selection: Any) -> Any:
447
+ """Apply this read preference to Selection."""
448
+ return member_with_tags_server_selector(
449
+ self.tag_sets, max_staleness_selectors.select(self.max_staleness, selection)
450
+ )
451
+
452
+
453
+ class _AggWritePref:
454
+ """Agg $out/$merge write preference.
455
+
456
+ * If there are readable servers and there is any pre-5.0 server, use
457
+ primary read preference.
458
+ * Otherwise use `pref` read preference.
459
+
460
+ :Parameters:
461
+ - `pref`: The read preference to use on MongoDB 5.0+.
462
+ """
463
+
464
+ __slots__ = ("pref", "effective_pref")
465
+
466
+ def __init__(self, pref):
467
+ self.pref = pref
468
+ self.effective_pref = ReadPreference.PRIMARY
469
+
470
+ def selection_hook(self, topology_description):
471
+ common_wv = topology_description.common_wire_version
472
+ if (
473
+ topology_description.has_readable_server(ReadPreference.PRIMARY_PREFERRED)
474
+ and common_wv
475
+ and common_wv < 13
476
+ ):
477
+ self.effective_pref = ReadPreference.PRIMARY
478
+ else:
479
+ self.effective_pref = self.pref
480
+
481
+ def __call__(self, selection):
482
+ """Apply this read preference to a Selection."""
483
+ return self.effective_pref(selection)
484
+
485
+ def __repr__(self):
486
+ return "_AggWritePref(pref=%r)" % (self.pref,)
487
+
488
+ # Proxy other calls to the effective_pref so that _AggWritePref can be
489
+ # used in place of an actual read preference.
490
+ def __getattr__(self, name):
491
+ return getattr(self.effective_pref, name)
492
+
493
+
494
+ _ALL_READ_PREFERENCES = (Primary, PrimaryPreferred, Secondary, SecondaryPreferred, Nearest)
495
+
496
+
497
+ def make_read_preference(
498
+ mode: int, tag_sets: Optional[_TagSets], max_staleness: int = -1
499
+ ) -> _ServerMode:
500
+ if mode == _PRIMARY:
501
+ if tag_sets not in (None, [{}]):
502
+ raise ConfigurationError("Read preference primary cannot be combined with tags")
503
+ if max_staleness != -1:
504
+ raise ConfigurationError(
505
+ "Read preference primary cannot be combined with maxStalenessSeconds"
506
+ )
507
+ return Primary()
508
+ return _ALL_READ_PREFERENCES[mode](tag_sets, max_staleness) # type: ignore
509
+
510
+
511
+ _MODES = (
512
+ "PRIMARY",
513
+ "PRIMARY_PREFERRED",
514
+ "SECONDARY",
515
+ "SECONDARY_PREFERRED",
516
+ "NEAREST",
517
+ )
518
+
519
+
520
+ class ReadPreference(object):
521
+ """An enum that defines the read preference modes supported by PyMongo.
522
+
523
+ See :doc:`/examples/high_availability` for code examples.
524
+
525
+ A read preference is used in three cases:
526
+
527
+ :class:`~pymongo.mongo_client.MongoClient` connected to a single mongod:
528
+
529
+ - ``PRIMARY``: Queries are allowed if the server is standalone or a replica
530
+ set primary.
531
+ - All other modes allow queries to standalone servers, to a replica set
532
+ primary, or to replica set secondaries.
533
+
534
+ :class:`~pymongo.mongo_client.MongoClient` initialized with the
535
+ ``replicaSet`` option:
536
+
537
+ - ``PRIMARY``: Read from the primary. This is the default, and provides the
538
+ strongest consistency. If no primary is available, raise
539
+ :class:`~pymongo.errors.AutoReconnect`.
540
+
541
+ - ``PRIMARY_PREFERRED``: Read from the primary if available, or if there is
542
+ none, read from a secondary.
543
+
544
+ - ``SECONDARY``: Read from a secondary. If no secondary is available,
545
+ raise :class:`~pymongo.errors.AutoReconnect`.
546
+
547
+ - ``SECONDARY_PREFERRED``: Read from a secondary if available, otherwise
548
+ from the primary.
549
+
550
+ - ``NEAREST``: Read from any member.
551
+
552
+ :class:`~pymongo.mongo_client.MongoClient` connected to a mongos, with a
553
+ sharded cluster of replica sets:
554
+
555
+ - ``PRIMARY``: Read from the primary of the shard, or raise
556
+ :class:`~pymongo.errors.OperationFailure` if there is none.
557
+ This is the default.
558
+
559
+ - ``PRIMARY_PREFERRED``: Read from the primary of the shard, or if there is
560
+ none, read from a secondary of the shard.
561
+
562
+ - ``SECONDARY``: Read from a secondary of the shard, or raise
563
+ :class:`~pymongo.errors.OperationFailure` if there is none.
564
+
565
+ - ``SECONDARY_PREFERRED``: Read from a secondary of the shard if available,
566
+ otherwise from the shard primary.
567
+
568
+ - ``NEAREST``: Read from any shard member.
569
+ """
570
+
571
+ PRIMARY = Primary()
572
+ PRIMARY_PREFERRED = PrimaryPreferred()
573
+ SECONDARY = Secondary()
574
+ SECONDARY_PREFERRED = SecondaryPreferred()
575
+ NEAREST = Nearest()
576
+
577
+
578
+ def read_pref_mode_from_name(name: str) -> int:
579
+ """Get the read preference mode from mongos/uri name."""
580
+ return _MONGOS_MODES.index(name)
581
+
582
+
583
+ class MovingAverage(object):
584
+ """Tracks an exponentially-weighted moving average."""
585
+
586
+ average: Optional[float]
587
+
588
+ def __init__(self) -> None:
589
+ self.average = None
590
+
591
+ def add_sample(self, sample: float) -> None:
592
+ if sample < 0:
593
+ # Likely system time change while waiting for hello response
594
+ # and not using time.monotonic. Ignore it, the next one will
595
+ # probably be valid.
596
+ return
597
+ if self.average is None:
598
+ self.average = sample
599
+ else:
600
+ # The Server Selection Spec requires an exponentially weighted
601
+ # average with alpha = 0.2.
602
+ self.average = 0.8 * self.average + 0.2 * sample
603
+
604
+ def get(self) -> Optional[float]:
605
+ """Get the calculated average, or None if no samples yet."""
606
+ return self.average
607
+
608
+ def reset(self) -> None:
609
+ self.average = None