Only set last_good if successfully verified

Rename last_connect to last_good
This commit is contained in:
Neil Booth 2017-04-03 21:35:35 +09:00
parent e0a79c313c
commit 2c43e89b05
3 changed files with 21 additions and 14 deletions

View File

@ -38,13 +38,13 @@ class Peer(object):
ATTRS = ('host', 'features', ATTRS = ('host', 'features',
# metadata # metadata
'source', 'ip_addr', 'good_ports', 'source', 'ip_addr', 'good_ports',
'last_connect', 'last_try', 'try_count') 'last_good', 'last_try', 'try_count')
FEATURES = ('pruning', 'server_version', 'protocol_min', 'protocol_max') FEATURES = ('pruning', 'server_version', 'protocol_min', 'protocol_max')
# This should be set by the application # This should be set by the application
DEFAULT_PORTS = {} DEFAULT_PORTS = {}
def __init__(self, host, features, source='unknown', ip_addr=None, def __init__(self, host, features, source='unknown', ip_addr=None,
good_ports=[], last_connect=0, last_try=0, try_count=0): good_ports=[], last_good=0, last_try=0, try_count=0):
'''Create a peer given a host name (or IP address as a string), '''Create a peer given a host name (or IP address as a string),
a dictionary of features, and a record of the source.''' a dictionary of features, and a record of the source.'''
assert isinstance(host, str) assert isinstance(host, str)
@ -59,7 +59,11 @@ class Peer(object):
self.source = source self.source = source
self.ip_addr = ip_addr self.ip_addr = ip_addr
self.good_ports = good_ports.copy() self.good_ports = good_ports.copy()
self.last_connect = last_connect # last_good represents the last connection that was
# successful *and* successfully verified, at which point
# try_count is set to 0. Failure to connect or failure to
# verify increment the try_count.
self.last_good = last_good
self.last_try = last_try self.last_try = last_try
self.try_count = try_count self.try_count = try_count
# Transient, non-persisted metadata # Transient, non-persisted metadata

View File

@ -500,7 +500,7 @@ class Controller(util.LoggedClass):
fmt = ('{:<30} {:<6} {:>5} {:>5} {:<17} {:>3} ' fmt = ('{:<30} {:<6} {:>5} {:>5} {:<17} {:>3} '
'{:>3} {:>8} {:>11} {:>11} {:>5} {:>20} {:<15}') '{:>3} {:>8} {:>11} {:>11} {:>5} {:>20} {:<15}')
yield fmt.format('Host', 'Status', 'TCP', 'SSL', 'Server', 'Min', yield fmt.format('Host', 'Status', 'TCP', 'SSL', 'Server', 'Min',
'Max', 'Pruning', 'Last Conn', 'Last Try', 'Max', 'Pruning', 'Last Good', 'Last Try',
'Tries', 'Source', 'IP Address') 'Tries', 'Source', 'IP Address')
for item in data: for item in data:
features = item['features'] features = item['features']
@ -514,7 +514,7 @@ class Controller(util.LoggedClass):
features['protocol_min'], features['protocol_min'],
features['protocol_max'], features['protocol_max'],
features['pruning'] or '', features['pruning'] or '',
time_fmt(item['last_connect']), time_fmt(item['last_good']),
time_fmt(item['last_try']), time_fmt(item['last_try']),
item['try_count'], item['try_count'],
item['source'][:20], item['source'][:20],

View File

@ -193,7 +193,6 @@ class PeerSession(JSONSession):
self.shutdown_connection() self.shutdown_connection()
def shutdown_connection(self): def shutdown_connection(self):
self.peer.last_connect = time.time()
is_good = not (self.failed or self.bad) is_good = not (self.failed or self.bad)
self.peer_mgr.set_verification_status(self.peer, self.kind, is_good) self.peer_mgr.set_verification_status(self.peer, self.kind, is_good)
self.close_connection() self.close_connection()
@ -249,9 +248,9 @@ class PeerManager(util.LoggedClass):
for peer in self.peers: for peer in self.peers:
if peer.bad: if peer.bad:
peer.status = PEER_BAD peer.status = PEER_BAD
elif peer.last_connect > cutoff: elif peer.last_good > cutoff:
peer.status = PEER_GOOD peer.status = PEER_GOOD
elif peer.last_connect: elif peer.last_good:
peer.status = PEER_STALE peer.status = PEER_STALE
else: else:
peer.status = PEER_NEVER peer.status = PEER_NEVER
@ -267,7 +266,7 @@ class PeerManager(util.LoggedClass):
return data return data
def peer_key(peer): def peer_key(peer):
return (peer.bad, -peer.last_connect) return (peer.bad, -peer.last_good)
return [peer_data(peer) for peer in sorted(self.peers, key=peer_key)] return [peer_data(peer) for peer in sorted(self.peers, key=peer_key)]
@ -358,13 +357,13 @@ class PeerManager(util.LoggedClass):
''' '''
cutoff = time.time() - STALE_SECS cutoff = time.time() - STALE_SECS
recent = [peer for peer in self.peers recent = [peer for peer in self.peers
if peer.last_connect > cutoff and if peer.last_good > cutoff and
not peer.bad and peer.is_public] not peer.bad and peer.is_public]
onion_peers = [] onion_peers = []
# Always report ourselves if valid (even if not public) # Always report ourselves if valid (even if not public)
peers = set(myself for myself in self.myselves peers = set(myself for myself in self.myselves
if myself.last_connect > cutoff) if myself.last_good > cutoff)
# Bucket the clearnet peers and select up to two from each # Bucket the clearnet peers and select up to two from each
buckets = defaultdict(list) buckets = defaultdict(list)
@ -409,6 +408,8 @@ class PeerManager(util.LoggedClass):
if version == 1: if version == 1:
peers = [] peers = []
for item in items: for item in items:
if 'last_connect' in item:
item['last_good'] = item.pop('last_connect')
try: try:
peers.append(Peer.deserialize(item)) peers.append(Peer.deserialize(item))
except Exception: except Exception:
@ -496,7 +497,7 @@ class PeerManager(util.LoggedClass):
return True return True
# Retry a good connection if it is about to turn stale # Retry a good connection if it is about to turn stale
if peer.try_count == 0: if peer.try_count == 0:
return peer.last_connect < nearly_stale_time return peer.last_good < nearly_stale_time
# Retry a failed connection if enough time has passed # Retry a failed connection if enough time has passed
return peer.last_try < now - WAKEUP_SECS * 2 ** peer.try_count return peer.last_try < now - WAKEUP_SECS * 2 ** peer.try_count
@ -549,16 +550,18 @@ class PeerManager(util.LoggedClass):
def set_verification_status(self, peer, kind, good): def set_verification_status(self, peer, kind, good):
'''Called when a verification succeeded or failed.''' '''Called when a verification succeeded or failed.'''
now = time.time()
if self.env.force_proxy or peer.is_tor: if self.env.force_proxy or peer.is_tor:
how = 'via {} over Tor'.format(kind) how = 'via {} over Tor'.format(kind)
else: else:
how = 'via {} at {}'.format(kind, peer.ip_addr) how = 'via {} at {}'.format(kind, peer.ip_addr)
status = 'verified' if good else 'failed to verify' status = 'verified' if good else 'failed to verify'
elapsed = time.time() - peer.last_try elapsed = now - peer.last_try
self.log_info('{} {} {} in {:.1f}s'.format(status, peer, how, elapsed)) self.log_info('{} {} {} in {:.1f}s'.format(status, peer, how, elapsed))
if good: if good:
peer.try_count = 0 peer.try_count = 0
peer.last_good = now
peer.source = 'peer' peer.source = 'peer'
# At most 2 matches if we're a host name, potentially several if # At most 2 matches if we're a host name, potentially several if
# we're an IP address (several instances can share a NAT). # we're an IP address (several instances can share a NAT).
@ -574,7 +577,7 @@ class PeerManager(util.LoggedClass):
def maybe_forget_peer(self, peer): def maybe_forget_peer(self, peer):
'''Forget the peer if appropriate, e.g. long-term unreachable.''' '''Forget the peer if appropriate, e.g. long-term unreachable.'''
if peer.last_connect and not peer.bad: if peer.last_good and not peer.bad:
try_limit = 10 try_limit = 10
else: else:
try_limit = 3 try_limit = 3