32
33
from bzrlib.lazy_import import lazy_import
33
34
lazy_import(globals(), """
34
37
from bzrlib import (
40
from bzrlib.smart import protocol
45
from bzrlib.smart import client, protocol
41
46
from bzrlib.transport import ssh
468
473
return self._medium._get_line()
476
class _DebugCounter(object):
477
"""An object that counts the HPSS calls made to each client medium.
479
When a medium is garbage-collected, or failing that when atexit functions
480
are run, the total number of calls made on that medium are reported via
485
self.counts = weakref.WeakKeyDictionary()
486
client._SmartClient.hooks.install_named_hook(
487
'call', self.increment_call_count, 'hpss call counter')
488
atexit.register(self.flush_all)
490
def track(self, medium):
491
"""Start tracking calls made to a medium.
493
This only keeps a weakref to the medium, so shouldn't affect the
496
medium_repr = repr(medium)
497
# Add this medium to the WeakKeyDictionary
498
self.counts[medium] = [0, medium_repr]
499
# Weakref callbacks are fired in reverse order of their association
500
# with the referenced object. So we add a weakref *after* adding to
501
# the WeakKeyDict so that we can report the value from it before the
502
# entry is removed by the WeakKeyDict's own callback.
503
ref = weakref.ref(medium, self.done)
505
def increment_call_count(self, params):
506
# Increment the count in the WeakKeyDictionary
507
value = self.counts[params.medium]
511
value = self.counts[ref]
512
count, medium_repr = value
513
# In case this callback is invoked for the same ref twice (by the
514
# weakref callback and by the atexit function), set the call count back
515
# to 0 so this item won't be reported twice.
518
trace.note('HPSS calls: %d %s', count, medium_repr)
521
for ref in list(self.counts.keys()):
524
_debug_counter = None
471
527
class SmartClientMedium(SmartMedium):
472
528
"""Smart client is a medium for sending smart protocol requests over."""
482
538
# _remote_version_is_before tracks the bzr version the remote side
483
539
# can be based on what we've seen so far.
484
540
self._remote_version_is_before = None
541
# Install debug hook function if debug flag is set.
542
if 'hpss' in debug.debug_flags:
543
global _debug_counter
544
if _debug_counter is None:
545
_debug_counter = _DebugCounter()
546
_debug_counter.track(self)
486
548
def _is_remote_before(self, version_tuple):
487
549
"""Is it possible the remote side supports RPCs for a given version?
784
846
raise errors.MediumNotConnected(self)
785
847
# We ignore the desired_count because on sockets it's more efficient to
786
848
# read large chunks (of _MAX_READ_SIZE bytes) at a time.
787
return self._socket.recv(_MAX_READ_SIZE)
850
return self._socket.recv(_MAX_READ_SIZE)
851
except socket.error, e:
852
if len(e.args) and e.args[0] == errno.ECONNRESET:
853
# Callers expect an empty string in that case
790
859
class SmartClientStreamMediumRequest(SmartClientMediumRequest):