3
]ð]V  ã            
   @   sð   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ed	d
ddddgƒedƒŽ ZejejfZG dd„ deƒZejejejejejejejejejejiZdd„ Zdd„ Zdd„ Z dd„ Z!dd„ Z"dd„ Z#dS )z*Represent a deployment of MongoDB servers.é    )Ú
namedtuple)Úcommon)ÚConfigurationError)ÚReadPreference)ÚServerDescription)Ú	Selection)ÚSERVER_TYPEZTopologyTypeÚSingleÚReplicaSetNoPrimaryÚReplicaSetWithPrimaryÚShardedÚUnknowné   c               @   sà   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Ze	dd„ ƒZ
e	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd „ ƒZe	d!d"„ ƒZd*d$d%„Zejfd&d'„Zd(d)„ Zd#S )+ÚTopologyDescriptionc             C   s
  || _ || _|| _|| _|| _|| _d| _xš| jjƒ D ]Œ}|jsBq6|j	dk	oV|j	t
jk}|jdk	ol|jt
jk }	|r–d|jd |jd |j	t
jf | _q6|	r6d|jd |jd |jt
jt
jf | _P q6W | j}
|
sØd| _n.tdd„ |
D ƒƒròd| _ntdd„ |
D ƒƒ| _dS )	aê  Representation of a deployment of MongoDB servers.

        :Parameters:
          - `topology_type`: initial type
          - `server_descriptions`: dict of (address, ServerDescription) for
            all seeds
          - `replica_set_name`: replica set name or None
          - `max_set_version`: greatest setVersion seen from a primary, or None
          - `max_election_id`: greatest electionId seen from a primary, or None
          - `topology_settings`: a TopologySettings
        Nz]Server at %s:%d requires wire version %d, but this version of PyMongo only supports up to %d.r   é   zgServer at %s:%d reports wire version %d, but this version of PyMongo requires at least %d (MongoDB %s).c             s   s   | ]}|j d kV  qd S )N)Úlogical_session_timeout_minutes)Ú.0Ús© r   ú?/tmp/pip-build-20mum3z4/pymongo/pymongo/topology_description.pyú	<genexpr>o   s   z/TopologyDescription.__init__.<locals>.<genexpr>c             s   s   | ]}|j V  qd S )N)r   )r   r   r   r   r   r   s   s   )Ú_topology_typeÚ_replica_set_nameÚ_server_descriptionsÚ_max_set_versionÚ_max_election_idÚ_topology_settingsÚ_incompatible_errÚvaluesÚis_server_type_knownÚmin_wire_versionr   ZMAX_SUPPORTED_WIRE_VERSIONÚmax_wire_versionZMIN_SUPPORTED_WIRE_VERSIONÚaddressZMIN_SUPPORTED_SERVER_VERSIONÚreadable_serversÚ_ls_timeout_minutesÚanyÚmin)ÚselfÚtopology_typeÚserver_descriptionsÚreplica_set_nameÚmax_set_versionÚmax_election_idZtopology_settingsr   Zserver_too_newZserver_too_oldr#   r   r   r   Ú__init__%   sB    

	
zTopologyDescription.__init__c             C   s   | j rt| j ƒ‚dS )z®Raise ConfigurationError if any server is incompatible.

        A server is incompatible if its wire protocol version range does not
        overlap with PyMongo's.
        N)r   r   )r'   r   r   r   Úcheck_compatiblev   s    z$TopologyDescription.check_compatiblec             C   s
   || j kS )N)r   )r'   r"   r   r   r   Ú
has_server   s    zTopologyDescription.has_serverc             C   s   t | t|ƒƒS )z;A copy of this description, with one server marked Unknown.)Úupdated_topology_descriptionr   )r'   r"   r   r   r   Úreset_server‚   s    z TopologyDescription.reset_serverc             C   sH   | j tjkrtj}n| j }tdd„ | jD ƒƒ}t||| j| j| j	| j
ƒS )z<A copy of this description, with all servers marked Unknown.c             s   s   | ]}|t |ƒfV  qd S )N)r   )r   r"   r   r   r   r   Ž   s   z,TopologyDescription.reset.<locals>.<genexpr>)r   ÚTOPOLOGY_TYPEr   r
   Údictr   r   r   r   r   r   )r'   r(   Úsdsr   r   r   Úreset†   s    zTopologyDescription.resetc             C   s
   | j jƒ S )zRDict of (address,
        :class:`~pymongo.server_description.ServerDescription`).)r   Úcopy)r'   r   r   r   r)   ™   s    z'TopologyDescription.server_descriptionsc             C   s   | j S )zThe type of this topology.)r   )r'   r   r   r   r(   ž   s    z!TopologyDescription.topology_typec             C   s   t j| j S )zUThe topology type as a human readable string.

        .. versionadded:: 3.4
        )r2   Ú_fieldsr   )r'   r   r   r   Útopology_type_name£   s    z&TopologyDescription.topology_type_namec             C   s   | j S )zThe replica set name.)r   )r'   r   r   r   r*   «   s    z$TopologyDescription.replica_set_namec             C   s   | j S )z1Greatest setVersion seen from a primary, or None.)r   )r'   r   r   r   r+   °   s    z#TopologyDescription.max_set_versionc             C   s   | j S )z1Greatest electionId seen from a primary, or None.)r   )r'   r   r   r   r,   µ   s    z#TopologyDescription.max_election_idc             C   s   | j S )z)Minimum logical session timeout, or None.)r$   )r'   r   r   r   r   º   s    z3TopologyDescription.logical_session_timeout_minutesc             C   s   dd„ | j jƒ D ƒS )z)List of Servers of types besides Unknown.c             S   s   g | ]}|j r|‘qS r   )r   )r   r   r   r   r   ú
<listcomp>Â   s    z5TopologyDescription.known_servers.<locals>.<listcomp>)r   r   )r'   r   r   r   Úknown_servers¿   s    z!TopologyDescription.known_serversc             C   s   t dd„ | jjƒ D ƒƒS )z7Whether there are any Servers of types besides Unknown.c             s   s   | ]}|j r|V  qd S )N)r   )r   r   r   r   r   r   È   s    z8TopologyDescription.has_known_servers.<locals>.<genexpr>)r%   r   r   )r'   r   r   r   Úhas_known_serversÅ   s    z%TopologyDescription.has_known_serversc             C   s   dd„ | j jƒ D ƒS )zList of readable Servers.c             S   s   g | ]}|j r|‘qS r   )Zis_readable)r   r   r   r   r   r9   Î   s    z8TopologyDescription.readable_servers.<locals>.<listcomp>)r   r   )r'   r   r   r   r#   Ë   s    z$TopologyDescription.readable_serversc             C   s"   | j }|rtdd„ | j D ƒƒS dS )z3Minimum of all servers' max wire versions, or None.c             s   s   | ]}|j V  qd S )N)r!   )r   r   r   r   r   r   Õ   s    z:TopologyDescription.common_wire_version.<locals>.<genexpr>N)r:   r&   )r'   Zserversr   r   r   Úcommon_wire_versionÐ   s    z'TopologyDescription.common_wire_versionc             C   s   | j jS )N)r   Úheartbeat_frequency)r'   r   r   r   r=   Ù   s    z'TopologyDescription.heartbeat_frequencyNc                s¼   ‡ fdd„}t |ddƒr@ˆ j}|r@||jk r@td||j|f ƒ‚ˆ jtjkrRˆ jS |rrˆ jƒ j	|ƒ}|rn|gS g S ˆ jtj
krŠtjˆ ƒ}n|tjˆ ƒƒ}|d k	r´|r´|j||jƒƒ}||ƒS )Nc                sB   | sg S ˆj }tdd„ | jD ƒƒ‰ |jd ‰‡ ‡fdd„| jD ƒS )Nc             s   s   | ]}|j V  qd S )N)Úround_trip_time)r   r   r   r   r   r   ç   s    zTTopologyDescription.apply_selector.<locals>.apply_local_threshold.<locals>.<genexpr>g     @�@c                s   g | ]}|j ˆ  ˆkr|‘qS r   )r>   )r   r   )ÚfastestÚ	thresholdr   r   r9   é   s    zUTopologyDescription.apply_selector.<locals>.apply_local_threshold.<locals>.<listcomp>)r   r&   r)   Zlocal_threshold_ms)Ú	selectionÚsettings)r'   )r?   r@   r   Úapply_local_thresholdß   s    
zATopologyDescription.apply_selector.<locals>.apply_local_thresholdr    r   zF%s requires min wire version %d, but topology's min wire version is %d)Úgetattrr<   r    r   r(   r2   r	   r:   r)   Úgetr   r   Zfrom_topology_descriptionZwith_server_descriptions)r'   Úselectorr"   Zcustom_selectorrC   Z	common_wvÚdescriptionrA   r   )r'   r   Úapply_selectorÝ   s*    
z"TopologyDescription.apply_selectorc             C   s   t jd|ƒ t| j|dƒƒS )aÒ  Does this topology have any readable servers available matching the
        given read preference?

        :Parameters:
          - `read_preference`: an instance of a read preference from
            :mod:`~pymongo.read_preferences`. Defaults to
            :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`.

        .. note:: When connected directly to a single server this method
          always returns ``True``.

        .. versionadded:: 3.4
        Úread_preferenceN)r   Zvalidate_read_preferencer%   rH   )r'   rI   r   r   r   Úhas_readable_server  s    z'TopologyDescription.has_readable_serverc             C   s   | j tjƒS )zÉDoes this topology have a writable server available?

        .. note:: When connected directly to a single server this method
          always returns ``True``.

        .. versionadded:: 3.4
        )rJ   r   ÚPRIMARY)r'   r   r   r   Úhas_writable_server  s    z'TopologyDescription.has_writable_server)N)Ú__name__Ú
__module__Ú__qualname__r-   r.   r/   r1   r5   r)   Úpropertyr(   r8   r*   r+   r,   r   r:   r;   r#   r<   r=   rH   r   rK   rJ   rL   r   r   r   r   r   $   s(   Q		
+r   c       	      C   s¾  |j }| j}| j}| j}| j}|j}| jƒ }|||< |tjkrTt	tj||||| j
ƒS |tjkrŒ|tjkrt|j|ƒ n|tjtjfkrŒt| }|tjkr²|tjtjfkr°|j|ƒ nø|tjk�r&|tjtjfkrÚ|j|ƒ nJ|tjkrþt|||||ƒ\}}}}n&|tjtjtjfk�rªt|||ƒ\}}n„|tjk�rª|tjtjfk�rX|j|ƒ t|ƒ}nR|tjk�r~t|||||ƒ\}}}}n,|tjtjtjfk�r¢t|||ƒ}nt|ƒ}t	|||||| j
ƒS )a„  Return an updated copy of a TopologyDescription.

    :Parameters:
      - `topology_description`: the current TopologyDescription
      - `server_description`: a new ServerDescription that resulted from
        an ismaster call

    Called after attempting (successfully or not) to call ismaster on the
    server at server_description.address. Does not modify topology_description.
    )r"   r(   r*   r+   r,   Úserver_typer)   r2   r	   r   r   r   r   Z
StandaloneÚpopZRSGhostÚ_SERVER_TYPE_TO_TOPOLOGY_TYPEr   ÚMongosr
   Ú	RSPrimaryÚ_update_rs_from_primaryÚRSSecondaryÚ	RSArbiterÚRSOtherÚ!_update_rs_no_primary_from_memberr   Ú_check_has_primaryÚ#_update_rs_with_primary_from_member)	Útopology_descriptionÚserver_descriptionr"   r(   Úset_namer+   r,   rQ   r4   r   r   r   r0   /  s|    






r0   c             C   s†   | j ƒ }t|jƒ ƒt|ƒkr | S x |D ]}||kr&t|ƒ||< q&W x&t|jƒ ƒD ]}||krP|j|ƒ qPW t| j|| j| j	| j
| jƒS )zñReturn an updated copy of a TopologyDescription.

    :Parameters:
      - `topology_description`: the current TopologyDescription
      - `seedlist`: a list of new seeds new ServerDescription that resulted from
        an ismaster call
    )r)   ÚsetÚkeysr   ÚlistrR   r   r(   r*   r+   r,   r   )r]   Zseedlistr4   r"   r   r   r   Ú)_updated_topology_description_srv_polling—  s     	
rc   c       
      C   s8  |dkr|j }n&||j kr6| j|jƒ t| ƒ|||fS ||f}d|jkr‚d|kr|||jkr||j}t|ƒ| |< t| ƒ|||fS |j}|jdk	r¤|dksž|j|kr¤|j}x:| jƒ D ].}|j	t
jkr®|j|jkr®t|jƒ| |j< P q®W x"|jD ]}|| krèt|ƒ| |< qèW x"t| ƒ|j D ]}	| j|	ƒ �qW t| ƒ|||fS )aj  Update topology description from a primary's ismaster response.

    Pass in a dict of ServerDescriptions, current replica set name, the
    ServerDescription we are processing, and the TopologyDescription's
    max_set_version and max_election_id if any.

    Returns (new topology type, new replica_set_name, new max_set_version,
    new max_election_id).
    N)r*   rR   r"   r[   Zelection_tupler   Zelection_idZset_versionr   rQ   r   rU   Ú	all_hostsr`   )
r4   r*   r^   r+   r,   Zmax_election_tupler"   ÚserverZnew_addressÚaddrr   r   r   rV   ¹  sJ    




rV   c             C   sJ   |dk	st ‚||jkr$| j|jƒ n|jrB|j|jkrB| j|jƒ t| ƒS )zØRS with known primary. Process a response from a non-primary.

    Pass in a dict of ServerDescriptions, current replica set name, and the
    ServerDescription we are processing.

    Returns new topology type.
    N)ÚAssertionErrorr*   rR   r"   Úmer[   )r4   r*   r^   r   r   r   r\     s    
r\   c             C   s~   t j}|dkr|j}n||jkr4| j|jƒ ||fS x"|jD ]}|| kr<t|ƒ| |< q<W |jrv|j|jkrv| j|jƒ ||fS )zòRS without known primary. Update from a non-primary's response.

    Pass in a dict of ServerDescriptions, current replica set name, and the
    ServerDescription we are processing.

    Returns (new topology type, new replica_set_name).
    N)r2   r
   r*   rR   r"   rd   r   rh   )r4   r*   r^   r(   r"   r   r   r   rZ     s    
rZ   c             C   s.   x(| j ƒ D ]}|jtjkr
tjS q
W tjS dS )z—Current topology type is ReplicaSetWithPrimary. Is primary still known?

    Pass in a dict of ServerDescriptions.

    Returns new topology type.
    N)r   rQ   r   rU   r2   r   r
   )r4   r   r   r   r   r[   <  s    
r[   N)$Ú__doc__Úcollectionsr   Zpymongor   Zpymongo.errorsr   Zpymongo.read_preferencesr   Zpymongo.server_descriptionr   Zpymongo.server_selectorsr   Zpymongo.server_typer   Úranger2   r   r   ZSRV_POLLING_TOPOLOGIESÚobjectr   rT   rU   r   rW   r
   rX   rY   rS   r0   rc   rV   r\   rZ   r[   r   r   r   r   Ú<module>   s2     h"L 