U
    ~fh                     @  s(  d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZmZmZmZmZmZ ddlmZmZmZ ddlmZmZmZmZmZmZmZm Z  ddl!m"Z" dd	l#m$Z$m%Z% dd
l&m'Z'm(Z(m)Z)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z: ddl;m<Z< ddl=m>Z> ddl?m@Z@ ddlAmBZBmCZCmDZDmEZEmFZF erddlGmHZH ddlImJZJ ddlKmLZLmMZM dZNeOeePjQZRdddddZSG dd dZTG dd  d ZUd!d!dd"d#d$ZVd%d%dd&d'd(ZWd.d)d*d)d+d,d-ZXdS )/z<Internal class to monitor a topology of one or more servers.    )annotationsN)Path)TYPE_CHECKINGAnyCallableMappingOptionalcast)_csotcommonhelpers_shared)ConnectionFailureInvalidOperationNetworkTimeoutNotPrimaryErrorOperationFailurePyMongoErrorServerSelectionTimeoutError
WriteError)Hello)_create_lock_Lock)_SDAM_LOGGER_SERVER_SELECTION_LOGGER
_debug_log_SDAMStatusMessage_ServerSelectionStatusMessage)PoolOptions)ServerDescription)	Selectionany_server_selectorarbiter_server_selectorsecondary_server_selectorwritable_server_selector)periodic_executor)_ServerSession_ServerSessionPool)
SrvMonitor)Pool)Server)SRV_POLLING_TOPOLOGIESTOPOLOGY_TYPETopologyDescription)_updated_topology_description_srv_pollingupdated_topology_description)ObjectId)TopologySettings)ClusterTime_AddressTz"weakref.ReferenceType[queue.Queue]bool)	queue_refreturnc                 C  sL   |  }|sdS z|  }W n tjk
r4   Y qHY qX |\}}||  qdS )NFT)
get_nowaitqueueEmpty)r4   qeventfnargs r=   @/tmp/pip-unpacked-wheel-36gvocj8/pymongo/synchronous/topology.pyprocess_events_queueR   s    

r?   c                	   @  s  e Zd ZdZddddZdddd	Zd
dddZddddddddddZdd
dddddddZdddddddddddZ	dddddddddd d!Z
dd"ddddd#d$d%Zdd'd(d(dd)d*d+Zdd'd(d(dd)d,d-Zd.dd/d0d1Zd.dd/d2d3Zd"d4d5d6d7Zd"d(d5d8d9Zddd:d;Zdd<d=d>d?Zd<dd@dAZd<ddBdCZdDddEdFZdGddHdIdJZdGddHdKdLZddNddOdPdQZdddRdSZdddTdUZdddVdWZedXddYdZZd[dd\d]Zdd^d_d`daZ d^ddbdcddZ!deddfdgZ"dddhdiZ#d"djd(dkdldmZ$d"djddkdndoZ%d"djddkdpdqZ&dddrdsZ'dddtduZ(d"dvd5dwdxZ)d"dvd5dydzZ*ddd=d{d|Z+ddd}d~Z,ddddZ-dd(dddZ.dNdddZ/dS )Topologyz*Monitor a topology of one or more servers.r0   )topology_settingsc                   s  |j | _ |jj| _| jd k	o"| jj| _| jd k	o6| jj| _d | _d | _	| jsR| jr`t
jdd| _ttjr~tt| j tjd | jr| jd k	st| j| jj| j ff || _t| | |jd d |}|| _ttji d d d | j}| jr| jd k	st| j| jj|| j| j ff ttjrBtt| j || jtjd |j D ]d}| jr~| jd k	sdt| j| jj!|| j ff ttjrHtt| j |d |d tj"d qHt#|$ | _%d| _&d| _'t( }t)|| _*| j+|| _,i | _-d | _.d | _/t0 | _1| js| jrf| jd k	s td	d
 fdd}t2j3t4j5t4j6|dd}t78| j|j9 || _	|:  d | _;| jj<d k	r| jj=st>| | j| _;d S )Nd   )maxsize
topologyIdmessagerE   ZpreviousDescriptionZnewDescriptionrF   r      )rE   
serverHost
serverPortrF   Fr3   r5   c                     s   t  S N)r?   r=   weakr=   r>   target   s    z!Topology.__init__.<locals>.targetZpymongo_events_thread)intervalZmin_intervalrO   name)?_topology_idZ_pool_options_event_listeners
_listenersZenabled_for_server_publish_serverZenabled_for_topology_publish_tp_events_Topology__events_executorr7   Queuer   isEnabledForloggingDEBUGr   r   ZSTART_TOPOLOGYAssertionErrorputZpublish_topology_opened	_settingsr,   Zget_topology_typeZget_server_descriptionsreplica_set_name_descriptionr+   Unknown$publish_topology_description_changedTOPOLOGY_CHANGEseedsZpublish_server_openedZSTART_SERVERlistserver_descriptions_seed_addresses_opened_closedr   r   _lockZcondition_class
_condition_servers_pid_max_cluster_timer&   _session_poolr$   ZPeriodicExecutorr   ZEVENTS_QUEUE_FREQUENCYMIN_HEARTBEAT_INTERVALweakrefrefcloseopen_srv_monitorfqdnload_balancedr'   )selfrA   Ztopology_descriptionZ
initial_tdseedrk   rO   executorr=   rM   r>   __init__f   s    
	     

	

zTopology.__init__NonerK   c              	   C  s   t  }| jdkr|| _nv|| jkr|| _tjdd dkrHdtfi}nddi}tjd| | j( | j	
 D ]}|  qn| j  W 5 Q R X | j |   W 5 Q R X dS )	a  Start monitoring, or restart after a fork.

        No effect if called multiple times.

        .. warning:: Topology is shared among multiple threads and is protected
          by mutual exclusion. Using Topology from a process other than the one
          that initialized it will emit a warning and may result in deadlock. To
          prevent this from happening, MongoClient must be created after any
          forking.

        N   )      Zskip_file_prefixes
stacklevel   MongoClient opened before fork. May not be entirely fork-safe, proceed with caution. See PyMongo's documentation for details: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/faq/#is-pymongo-fork-safe-)r   )osgetpidrn   sysversion_info_pymongo_dirwarningswarnrk   rm   valuesrt   rp   reset_ensure_opened)ry   pidkwargsserverr=   r=   r>   ru      s&    

 
zTopology.openfloatc                 C  s   t  }|d kr| jjS |S rL   )r
   	remainingr_   server_selection_timeout)ry   timeoutr=   r=   r>   get_server_selection_timeout   s    z%Topology.get_server_selection_timeoutNz Callable[[Selection], Selection]strzOptional[float]zOptional[_Address]zOptional[int]list[Server])selector	operationr   addressoperation_idr5   c              
     sX   |dkr   }n|} j2  |||||} fdd|D W  5 Q R  S Q R X dS )a  Return a list of Servers matching selector, or time out.

        :param selector: function that takes a list of Servers and returns
            a subset of them.
        :param operation: The name of the operation that the server is being selected for.
        :param server_selection_timeout: maximum seconds to wait.
            If not provided, the default value common.SERVER_SELECTION_TIMEOUT
            is used.
        :param address: optional server address to select.

        Calls self.open() if needed.

        Raises exc:`ServerSelectionTimeoutError` after
        `server_selection_timeout` if no matching servers are found.
        Nc                   s   g | ]}t t |jqS r=   )r	   r)   get_server_by_addressr   .0sdry   r=   r>   
<listcomp>  s    z+Topology.select_servers.<locals>.<listcomp>)r   rk   _select_servers_loop)ry   r   r   r   r   r   Zserver_timeoutrg   r=   r   r>   select_servers   s    
    
zTopology.select_serverszlist[ServerDescription])r   r   r   r   r   r5   c           
      C  sL  t  }|| }d}ttjr@tttj|||| j	| j	j
jd | jj||| jjd}	|	s>|dksl||krttjrtttj|||| j	| j	j
j| |d t| | d| d| j	|stttj|||| j	| j	j
jt|t   d d	}|   |   | jtj | j  t  }| jj||| jjd}	qV| j  |	S )
z7select_servers() guts. Hold the lock when calling this.F)rF   r   r   operationIdtopologyDescriptionclientId)Zcustom_selectorr   )rF   r   r   r   r   r   Zfailurez, Timeout: zs, Topology Description: )rF   r   r   r   r   r   ZremainingTimeMST)time	monotonicr   rZ   r[   r\   r   r   ZSTARTEDdescription_topology_settingsrR   ra   Zapply_selectorr_   Zserver_selectorZFAILED_error_messager   ZWAITINGintr   _request_check_allrl   waitr   rq   Zcheck_compatible)
ry   r   r   r   r   r   nowZend_timeZlogged_waitingrg   r=   r=   r>   r   #  st    	
  


  
zTopology._select_servers_loopOptional[list[Server]]r)   )r   r   r   r   deprioritized_serversr   r5   c           
      C  s\   |  |||||}t||}t|dkr0|d S t|d\}}	|jj|	jjkrT|S |	S d S )NrH   r   r~   )r   _filter_serverslenrandomsamplepoolZoperation_count)
ry   r   r   r   r   r   r   serversZserver1Zserver2r=   r=   r>   _select_servero  s    	    
zTopology._select_serverc                 C  sp   | j ||||||d}t r,t|jj ttj	rlt
ttj|||| j| jjj|jjd |jjd d	 |S )zALike select_servers, but choose a random server if several match.r   r   rH   )rF   r   r   r   r   r   rI   rJ   )r   r
   Zget_timeoutZset_rttr   Zmin_round_trip_timer   rZ   r[   r\   r   r   Z	SUCCEEDEDr   rR   r   )ry   r   r   r   r   r   r   r   r=   r=   r>   select_server  s.    


zTopology.select_serverr2   )r   r   r   r   r5   c                 C  s   | j t||||dS )a=  Return a Server for "address", reconnecting if necessary.

        If the server's type is not known, request an immediate check of all
        servers. Time out after "server_selection_timeout" if the server
        cannot be reached.

        :param address: A (host, port) pair.
        :param operation: The name of the operation that the server is being selected for.
        :param server_selection_timeout: maximum seconds to wait.
            If not provided, the default value
            common.SERVER_SELECTION_TIMEOUT is used.
        :param operation_id: The unique id of the current operation being performed. Defaults to None if not provided.

        Calls self.open() if needed.

        Raises exc:`ServerSelectionTimeoutError` after
        `server_selection_timeout` if no matching servers are found.
        r   )r   r    )ry   r   r   r   r   r=   r=   r>   select_server_by_address  s    z!Topology.select_server_by_addressFr   r3   )server_description
reset_poolinterrupt_connectionsr5   c           	      C  s  | j }|j|j }t||r dS t| j |}|jsD|jr`|jtj	kr`| j
|j}|r`|j  ||k}| jr|s| jdk	st| j| jj|||j| jff || _ |   | |j | jr|s| jdk	st| j| jj|| j | jff ttjr|stt| j|| j tj d | j!rJ|jtj"krJ| j jt#krJ| j!$  |rr| j
|j}|rr|jj%|d | j&'  dS )ziProcess a new ServerDescription on an opened topology.

        Hold the lock when calling this.
        NrG   )r   )(ra   Z_server_descriptionsr   _is_stale_server_descriptionr.   Zis_readableZis_server_type_knowntopology_typer+   Singlerm   getr   readyrU   rW   r]   r^   rT   Z"publish_server_description_changedrR   _update_servers_receive_cluster_time_no_lockcluster_timerV   rc   r   rZ   r[   r\   r   r   rd   rv   rb   r*   rt   r   rl   
notify_all)	ry   r   r   r   td_oldZsd_oldZnew_tdr   Zsuppress_eventr=   r=   r>   _process_change  sd    








zTopology._process_changec              	   C  s8   | j ( | jr*| j|jr*| ||| W 5 Q R X dS )z>Process a new ServerDescription after an hello call completes.N)rk   ri   ra   
has_serverr   r   )ry   r   r   r   r=   r=   r>   	on_change  s    	zTopology.on_changezlist[tuple[str, Any]])seedlistr5   c                 C  s   | j }|jtkrdS t| j || _ |   | jr\| jdk	s>t| j| j	j
|| j | jff ttjrtt| j|| j tjd dS )z_Process a new seedlist on an opened topology.
        Hold the lock when calling this.
        NrG   )ra   r   r*   r-   r   rV   rW   r]   r^   rT   rc   rR   r   rZ   r[   r\   r   r   rd   )ry   r   r   r=   r=   r>   _process_srv_update%  s(    
zTopology._process_srv_updatec              	   C  s&   | j  | jr| | W 5 Q R X dS )z?Process a new list of nodes obtained from scanning SRV records.N)rk   ri   r   )ry   r   r=   r=   r>   on_srv_updateA  s    zTopology.on_srv_updatezOptional[Server])r   r5   c                 C  s   | j |S )aJ  Get a Server or None.

        Returns the current version of the server immediately, even if it's
        Unknown or absent from the topology. Only use this in unittests.
        In driver code, use select_server_by_address, since then you're
        assured a recent view of the server's type and wire protocol version.
        )rm   r   ry   r   r=   r=   r>   r   H  s    zTopology.get_server_by_addressc                 C  s
   || j kS rL   )rm   r   r=   r=   r>   r   R  s    zTopology.has_serverc              
   C  sP   | j @ | jj}|tjkr(W 5 Q R  dS t|  d jW  5 Q R  S Q R X dS )z!Return primary's address or None.Nr   )rk   ra   r   r+   ReplicaSetWithPrimaryr#   _new_selectionr   )ry   r   r=   r=   r>   get_primaryU  s
    
zTopology.get_primaryzset[_Address])r   r5   c              
   C  sb   | j R | jj}|tjtjfkr2t W  5 Q R  S dd t||  D W  5 Q R  S Q R X dS )z+Return set of replica set member addresses.c                 S  s   h | ]
}|j qS r=   )r   r   r=   r=   r>   	<setcomp>j  s     z4Topology._get_replica_set_members.<locals>.<setcomp>N)	rk   ra   r   r+   r   ReplicaSetNoPrimarysetiterr   )ry   r   r   r=   r=   r>   _get_replica_set_members_  s    z!Topology._get_replica_set_membersc                 C  s
   |  tS )z"Return set of secondary addresses.)r   r"   r   r=   r=   r>   get_secondariesl  s    zTopology.get_secondariesc                 C  s
   |  tS )z Return set of arbiter addresses.)r   r!   r   r=   r=   r>   get_arbitersp  s    zTopology.get_arbiterszOptional[ClusterTime]c                 C  s   | j S )z1Return a document, the highest seen $clusterTime.ro   r   r=   r=   r>   max_cluster_timet  s    zTopology.max_cluster_timeOptional[Mapping[str, Any]])r   r5   c                 C  s&   |r"| j r|d | j d kr"|| _ d S )NZclusterTimer   ry   r   r=   r=   r>   r   x  s    z&Topology._receive_cluster_time_no_lockc              	   C  s    | j  | | W 5 Q R X d S rL   )rk   r   r   r=   r=   r>   receive_cluster_time  s    zTopology.receive_cluster_time   r   )	wait_timer5   c              	   C  s*   | j  |   | j| W 5 Q R X dS )z=Wake all monitors, wait for at least one to check its server.N)rk   r   rl   r   )ry   r   r=   r=   r>   request_check_all  s    zTopology.request_check_allc                 C  s   | j jtjkr| j jS | j jS )z~Return a list of all data-bearing servers.

        This includes any server that might be selected for an operation.
        )ra   r   r+   r   known_serversZreadable_serversr   r=   r=   r>   data_bearing_servers  s    zTopology.data_bearing_serversc                 C  s   g }| j 6 |  D ]&}| j|j }|||jj f qW 5 Q R X |D ]^\}}z|j| W qJ t	k
r } z&t
|d|dd }| |jj|  W 5 d }~X Y qJX qJd S )Nr   F)rk   r   rm   r   appendr   genZget_overallZremove_stale_socketsr   _ErrorContexthandle_errorr   )ry   r   r   r   Z
generationexcctxr=   r=   r>   update_pool  s    "zTopology.update_poolc              	   C  sh  | j z | j}| j D ]}|  q| j | _| j  D ]\}}|| jkr@|| j| _q@| j	rp| j	  d| _
d| _W 5 Q R X | jr| jdk	stttji | jj| jj| jj| jj| _| j| jj|| j| jff | j| jj| jff ttjr.tt| j|| jt j!d tt| jt j"d | j#s>| jrd| j$  | j$%d t&t'(| j dS )zClear pools and terminate monitors. Topology does not reopen on
        demand. Any further operations will raise
        :exc:`~.errors.InvalidOperation`.
        FTNrG   rD   rH   ))rk   ra   rm   r   rt   r   rg   itemsr   rv   ri   rj   rV   rW   r]   r,   r+   rb   r`   Zmax_set_versionZmax_election_idr   r^   rT   rc   rR   Zpublish_topology_closedr   rZ   r[   r\   r   r   rd   ZSTOP_TOPOLOGYrU   rX   joinr?   rr   rs   )ry   Zold_tdr   r   r   r=   r=   r>   rt     s`    



  
zTopology.closer,   c                 C  s   | j S rL   )ra   r   r=   r=   r>   r     s    zTopology.descriptionzlist[_ServerSession]c                 C  s
   | j  S )z"Pop all session ids from the pool.)rp   pop_allr   r=   r=   r>   pop_all_sessions  s    zTopology.pop_all_sessionsr%   )session_timeout_minutesr5   c                 C  s   | j |S )z>Start or resume a server session, or raise ConfigurationError.)rp   get_server_session)ry   r   r=   r=   r>   r     s    zTopology.get_server_session)server_sessionr5   c                 C  s   | j | d S rL   )rp   return_server_session)ry   r   r=   r=   r>   r     s    zTopology.return_server_sessionr   c                 C  s   t | jS )zmA Selection object, initially including all known servers.

        Hold the lock when calling this.
        )r   Zfrom_topology_descriptionra   r   r=   r=   r>   r     s    zTopology._new_selectionc              	   C  s   | j rtd| jsd| _|   | js.| jr8| j  | jrT| j	j
tkrT| j  | jjr| t| jd td| jdd | j D ]}|  qdS )z[Start monitors, or restart after a fork.

        Hold the lock when calling this.
        z"Cannot use MongoClient after closeTr   rH      )okZ	serviceIdZmaxWireVersionN)rj   r   ri   r   rV   rU   rX   ru   rv   r   r   r*   r_   rx   r   r   rh   r   rR   rm   r   ry   r   r=   r=   r>   r      s$    

zTopology._ensure_openedr   )r   err_ctxr5   c                 C  sp   | j |}|d krdS |j|j|jr.dS |jj}|j}d }|rft	|drft
|jtrf|jd}t||S )NTdetailsZtopologyVersion)rm   r   _poolZstale_generationsock_generation
service_idr   topology_versionerrorhasattr
isinstancer   dict _is_stale_error_topology_version)ry   r   r   r   Zcur_tvr   error_tvr=   r=   r>   _is_stale_error!  s    zTopology._is_stale_errorc           	      C  s`  |  ||rd S | j| }|j}|j}| jjr<|s<|js<d S t|trP|jrPd S t|t	r^d S t|t
tfr t|dr|j}n t|t
rdnd }|jd|}|tjkr|tjk}| jjs| t||d |s|jdkr|| |  n.|js\| jjs| t||d || n<t|tr\| jjsH| t||d || |j  d S )Ncodei{'  r      )r  rm   r   r   r_   rx   completed_handshaker   r   r   r   r   r   r  r   r   r   Z_NOT_PRIMARY_CODESZ_SHUTDOWN_CODESr   r   max_wire_versionr   request_checkr   _monitorZcancel_check)	ry   r   r   r   r   r   Zerr_codedefaultZis_shutting_downr=   r=   r>   _handle_error5  s@    

	







zTopology._handle_errorc              	   C  s"   | j  | || W 5 Q R X dS )zHandle an application error.

        May reset the server to Unknown, clear the pool, and request an
        immediate check depending on the error and the context.
        N)rk   r  )ry   r   r   r=   r=   r>   r   w  s    zTopology.handle_errorc                 C  s   | j  D ]}|  q
dS )z3Wake all monitors. Hold the lock when calling this.N)rm   r   r  r   r=   r=   r>   r     s    zTopology._request_check_allc              	   C  s  | j   D ]\}}|| jkr| jj|| | || jd}d}| jr\| jdk	r\t	
| j}t|| ||| j| j|d}|| j|< |  q| j| jj}|| j| _||jkr| j| j|j qt| j D ](\}}| j |s|  | j| qdS )zrSync our Servers from TopologyDescription.server_descriptions.

        Hold the lock while calling this.
        )r   Ztopologyr   rA   N)r   r   monitorZtopology_idZ	listenersevents)ra   rg   r   rm   r_   Zmonitor_class_create_pool_for_monitorrU   rW   rr   rs   r)   _create_pool_for_serverrR   rT   ru   r   is_writabler   Zupdate_is_writablerf   r   rt   pop)ry   r   r   r  rN   r   Zwas_writabler=   r=   r>   r     s:    
	


zTopology._update_serversr(   c                 C  s   | j j|| j j| jdS )N)	client_id)r_   
pool_classpool_optionsrR   r   r=   r=   r>   r    s
      z Topology._create_pool_for_serverc                 C  sH   | j j}t|j|j|j|j|j|j|jd|j	d	}| j j
||d| jdS )NF)	connect_timeoutsocket_timeoutssl_contexttls_allow_invalid_hostnamesZevent_listenersappnamedriverZpause_enabled
server_api)Z	handshaker  )r_   r  r   r  Z_ssl_contextr  rS   r  r  r  r  rR   )ry   r   optionsZmonitor_pool_optionsr=   r=   r>   r    s$       z!Topology._create_pool_for_monitorc                   s*  | j jtjtjfk}|rd}n| j jtjkr2d}nd}| j jrl|tkrX|rNdS d| S nd| d| dS nt| j 	 }t| j 	 
 }|s|rd	|| jjS d
| S |d j t fdd|dd D }|r dkrd| S |r
t|| js
d| S t S ddd |D S dS )zeFormat an error message if server selection fails.

        Hold the lock when calling this.
        zreplica set membersZmongosesr   zNo primary available for writeszNo %s available for writeszNo z match selector ""z)No {} available for replica set name "{}"zNo %s availabler   c                 3  s   | ]}|j  kV  qd S rL   r  r   r   r  r=   r>   	<genexpr>  s     z*Topology._error_message.<locals>.<genexpr>rH   NzNo %s found yetz\Could not reach any servers in %s. Replica set is configured with internal hostnames or IPs?,c                 s  s   | ]}|j rt|j V  qd S rL   )r   r   r  r=   r=   r>   r    s      )ra   r   r+   r   r   ZShardedr   r#   rf   rg   r   formatr_   r`   r   allr   intersectionrh   r   r   )ry   r   Zis_replica_setZserver_plural	addressesr   Zsamer=   r  r>   r     sH    

zTopology._error_messagec                 C  s*   d}| j sd}d| jj d| | jdS )N zCLOSED < >)ri   	__class____name__ra   )ry   msgr=   r=   r>   __repr__  s    zTopology.__repr__z>tuple[tuple[_Address, ...], Optional[str], Optional[str], str]c                 C  s"   | j }tt|j|j|j|jfS )z?The properties to use for MongoClient/Topology equality checks.)r_   tuplesortedre   r`   rw   Zsrv_service_name)ry   tsr=   r=   r>   eq_props
  s    zTopology.eq_propsobject)otherr5   c                 C  s    t || jr|  | kS tS rL   )r   r)  r0  NotImplemented)ry   r2  r=   r=   r>   __eq__  s    zTopology.__eq__c                 C  s   t |  S rL   )hashr0  r   r=   r=   r>   __hash__  s    zTopology.__hash__)NNN)NNNN)NNNN)NN)FF)FF)r   )0r*  
__module____qualname____doc__r|   ru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rt   propertyr   r   r   r   r   r   r  r  r   r   r   r  r  r   r,  r0  r4  r6  r=   r=   r=   r>   r@   c   s|   h)   %P        &  $  M  

	?!B	*:r@   c                   @  s&   e Zd ZdZddddddddZd	S )
r   z.An error with context for SDAM error handling.BaseExceptionr   r3   zOptional[ObjectId]r   r  r   r  r   c                 C  s"   || _ || _|| _|| _|| _d S rL   r<  )ry   r   r  r   r  r   r=   r=   r>   r|     s
    z_ErrorContext.__init__N)r*  r7  r8  r9  r|   r=   r=   r=   r>   r     s   r   r   )
current_tvr  r5   c                 C  s8   | dks|dkrdS | d |d kr(dS | d |d kS )z9Return True if the error's topologyVersion is <= current.NF	processIdcounterr=   )r=  r  r=   r=   r>   r   *  s
    r   r   )
current_sdnew_sdr5   c                 C  sF   | j |j  }}|dks|dkr"dS |d |d kr6dS |d |d kS )z4Return True if the new topologyVersion is < current.NFr>  r?  )r   )r@  rA  r=  Znew_tvr=   r=   r>   r   5  s    r   r   r   )
candidatesr   r5   c                   s"    s| S  fdd| D }|p | S )zBFilter out deprioritized servers from a list of server candidates.c                   s   g | ]}| kr|qS r=   r=   r  r   r=   r>   r   F  s      z#_filter_servers.<locals>.<listcomp>r=   )rB  r   filteredr=   rC  r>   r   ?  s    r   )N)Yr9  
__future__r   r[   r   r7   r   r   r   r   rr   pathlibr   typingr   r   r   r   r   r	   Zpymongor
   r   r   Zpymongo.errorsr   r   r   r   r   r   r   r   Zpymongo.hellor   Zpymongo.lockr   r   Zpymongo.loggerr   r   r   r   r   Zpymongo.pool_optionsr   Zpymongo.server_descriptionr   Zpymongo.server_selectorsr   r    r!   r"   r#   Zpymongo.synchronousr$   Z"pymongo.synchronous.client_sessionr%   r&   Zpymongo.synchronous.monitorr'   Zpymongo.synchronous.poolr(   Zpymongo.synchronous.serverr)   Zpymongo.topology_descriptionr*   r+   r,   r-   r.   Zbsonr/   Zpymongo.synchronous.settingsr0   Zpymongo.typingsr1   r2   Z_IS_SYNCr   __file__parentr   r?   r@   r   r   r   r   r=   r=   r=   r>   <module>   sZ    (
       < 