~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/medium.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-08-31 00:27:39 UTC
  • mfrom: (4664.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090831002739-vd6487doda1b2k9h
(robertc) Fix bug 416732 by not adding root directories to expected
        items when checking non rich root repositories. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""The 'medium' layer for the smart servers and clients.
18
18
 
24
24
bzrlib/transport/smart/__init__.py.
25
25
"""
26
26
 
 
27
import errno
27
28
import os
28
29
import socket
29
30
import sys
31
32
 
32
33
from bzrlib.lazy_import import lazy_import
33
34
lazy_import(globals(), """
 
35
import atexit
 
36
import weakref
34
37
from bzrlib import (
 
38
    debug,
35
39
    errors,
36
 
    osutils,
37
40
    symbol_versioning,
 
41
    trace,
 
42
    ui,
38
43
    urlutils,
39
44
    )
40
 
from bzrlib.smart import protocol
 
45
from bzrlib.smart import client, protocol, request, vfs
41
46
from bzrlib.transport import ssh
42
47
""")
43
 
 
 
48
#usually already imported, and getting IllegalScoperReplacer on it here.
 
49
from bzrlib import osutils
44
50
 
45
51
# We must not read any more than 64k at a time so we don't risk "no buffer
46
52
# space available" errors on some platforms.  Windows in particular is likely
82
88
 
83
89
def _get_line(read_bytes_func):
84
90
    """Read bytes using read_bytes_func until a newline byte.
85
 
    
 
91
 
86
92
    This isn't particularly efficient, so should only be used when the
87
93
    expected size of the line is quite short.
88
 
    
 
94
 
89
95
    :returns: a tuple of two strs: (line, excess)
90
96
    """
91
97
    newline_pos = -1
107
113
 
108
114
    def __init__(self):
109
115
        self._push_back_buffer = None
110
 
        
 
116
 
111
117
    def _push_back(self, bytes):
112
118
        """Return unused bytes to the medium, because they belong to the next
113
119
        request(s).
147
153
 
148
154
    def _get_line(self):
149
155
        """Read bytes from this request's response until a newline byte.
150
 
        
 
156
 
151
157
        This isn't particularly efficient, so should only be used when the
152
158
        expected size of the line is quite short.
153
159
 
156
162
        line, excess = _get_line(self.read_bytes)
157
163
        self._push_back(excess)
158
164
        return line
159
 
 
 
165
 
 
166
    def _report_activity(self, bytes, direction):
 
167
        """Notify that this medium has activity.
 
168
 
 
169
        Implementations should call this from all methods that actually do IO.
 
170
        Be careful that it's not called twice, if one method is implemented on
 
171
        top of another.
 
172
 
 
173
        :param bytes: Number of bytes read or written.
 
174
        :param direction: 'read' or 'write' or None.
 
175
        """
 
176
        ui.ui_factory.report_transport_activity(self, bytes, direction)
 
177
 
160
178
 
161
179
class SmartServerStreamMedium(SmartMedium):
162
180
    """Handles smart commands coming over a stream.
167
185
    One instance is created for each connected client; it can serve multiple
168
186
    requests in the lifetime of the connection.
169
187
 
170
 
    The server passes requests through to an underlying backing transport, 
 
188
    The server passes requests through to an underlying backing transport,
171
189
    which will typically be a LocalTransport looking at the server's filesystem.
172
190
 
173
191
    :ivar _push_back_buffer: a str of bytes that have been read from the stream
218
236
 
219
237
    def _serve_one_request(self, protocol):
220
238
        """Read one request from input, process, send back a response.
221
 
        
 
239
 
222
240
        :param protocol: a SmartServerRequestProtocol.
223
241
        """
224
242
        try:
263
281
                self.finished = True
264
282
                return
265
283
            protocol.accept_bytes(bytes)
266
 
        
 
284
 
267
285
        self._push_back(protocol.unused_data)
268
286
 
269
287
    def _read_bytes(self, desired_count):
270
 
        # We ignore the desired_count because on sockets it's more efficient to
271
 
        # read large chunks (of _MAX_READ_SIZE bytes) at a time.
272
 
        return self.socket.recv(_MAX_READ_SIZE)
 
288
        return _read_bytes_from_socket(
 
289
            self.socket.recv, desired_count, self._report_activity)
273
290
 
274
291
    def terminate_due_to_error(self):
275
292
        # TODO: This should log to a server log file, but no such thing
278
295
        self.finished = True
279
296
 
280
297
    def _write_out(self, bytes):
281
 
        osutils.send_all(self.socket, bytes)
 
298
        osutils.send_all(self.socket, bytes, self._report_activity)
282
299
 
283
300
 
284
301
class SmartServerPipeStreamMedium(SmartServerStreamMedium):
345
362
    request.finished_reading()
346
363
 
347
364
    It is up to the individual SmartClientMedium whether multiple concurrent
348
 
    requests can exist. See SmartClientMedium.get_request to obtain instances 
349
 
    of SmartClientMediumRequest, and the concrete Medium you are using for 
 
365
    requests can exist. See SmartClientMedium.get_request to obtain instances
 
366
    of SmartClientMediumRequest, and the concrete Medium you are using for
350
367
    details on concurrency and pipelining.
351
368
    """
352
369
 
361
378
    def accept_bytes(self, bytes):
362
379
        """Accept bytes for inclusion in this request.
363
380
 
364
 
        This method may not be be called after finished_writing() has been
 
381
        This method may not be called after finished_writing() has been
365
382
        called.  It depends upon the Medium whether or not the bytes will be
366
383
        immediately transmitted. Message based Mediums will tend to buffer the
367
384
        bytes until finished_writing() is called.
398
415
    def _finished_reading(self):
399
416
        """Helper for finished_reading.
400
417
 
401
 
        finished_reading checks the state of the request to determine if 
 
418
        finished_reading checks the state of the request to determine if
402
419
        finished_reading is allowed, and if it is hands off to _finished_reading
403
420
        to perform the action.
404
421
        """
418
435
    def _finished_writing(self):
419
436
        """Helper for finished_writing.
420
437
 
421
 
        finished_writing checks the state of the request to determine if 
 
438
        finished_writing checks the state of the request to determine if
422
439
        finished_writing is allowed, and if it is hands off to _finished_writing
423
440
        to perform the action.
424
441
        """
444
461
        read_bytes checks the state of the request to determing if bytes
445
462
        should be read. After that it hands off to _read_bytes to do the
446
463
        actual read.
447
 
        
 
464
 
448
465
        By default this forwards to self._medium.read_bytes because we are
449
466
        operating on the medium's stream.
450
467
        """
455
472
        if not line.endswith('\n'):
456
473
            # end of file encountered reading from server
457
474
            raise errors.ConnectionReset(
458
 
                "please check connectivity and permissions",
459
 
                "(and try -Dhpss if further diagnosis is required)")
 
475
                "Unexpected end of message. Please check connectivity "
 
476
                "and permissions, and report a bug if problems persist.")
460
477
        return line
461
478
 
462
479
    def _read_line(self):
463
480
        """Helper for SmartClientMediumRequest.read_line.
464
 
        
 
481
 
465
482
        By default this forwards to self._medium._get_line because we are
466
483
        operating on the medium's stream.
467
484
        """
468
485
        return self._medium._get_line()
469
486
 
470
487
 
 
488
class _DebugCounter(object):
 
489
    """An object that counts the HPSS calls made to each client medium.
 
490
 
 
491
    When a medium is garbage-collected, or failing that when atexit functions
 
492
    are run, the total number of calls made on that medium are reported via
 
493
    trace.note.
 
494
    """
 
495
 
 
496
    def __init__(self):
 
497
        self.counts = weakref.WeakKeyDictionary()
 
498
        client._SmartClient.hooks.install_named_hook(
 
499
            'call', self.increment_call_count, 'hpss call counter')
 
500
        atexit.register(self.flush_all)
 
501
 
 
502
    def track(self, medium):
 
503
        """Start tracking calls made to a medium.
 
504
 
 
505
        This only keeps a weakref to the medium, so shouldn't affect the
 
506
        medium's lifetime.
 
507
        """
 
508
        medium_repr = repr(medium)
 
509
        # Add this medium to the WeakKeyDictionary
 
510
        self.counts[medium] = dict(count=0, vfs_count=0,
 
511
                                   medium_repr=medium_repr)
 
512
        # Weakref callbacks are fired in reverse order of their association
 
513
        # with the referenced object.  So we add a weakref *after* adding to
 
514
        # the WeakKeyDict so that we can report the value from it before the
 
515
        # entry is removed by the WeakKeyDict's own callback.
 
516
        ref = weakref.ref(medium, self.done)
 
517
 
 
518
    def increment_call_count(self, params):
 
519
        # Increment the count in the WeakKeyDictionary
 
520
        value = self.counts[params.medium]
 
521
        value['count'] += 1
 
522
        try:
 
523
            request_method = request.request_handlers.get(params.method)
 
524
        except KeyError:
 
525
            # A method we don't know about doesn't count as a VFS method.
 
526
            return
 
527
        if issubclass(request_method, vfs.VfsRequest):
 
528
            value['vfs_count'] += 1
 
529
 
 
530
    def done(self, ref):
 
531
        value = self.counts[ref]
 
532
        count, vfs_count, medium_repr = (
 
533
            value['count'], value['vfs_count'], value['medium_repr'])
 
534
        # In case this callback is invoked for the same ref twice (by the
 
535
        # weakref callback and by the atexit function), set the call count back
 
536
        # to 0 so this item won't be reported twice.
 
537
        value['count'] = 0
 
538
        value['vfs_count'] = 0
 
539
        if count != 0:
 
540
            trace.note('HPSS calls: %d (%d vfs) %s',
 
541
                       count, vfs_count, medium_repr)
 
542
 
 
543
    def flush_all(self):
 
544
        for ref in list(self.counts.keys()):
 
545
            self.done(ref)
 
546
 
 
547
_debug_counter = None
 
548
 
 
549
 
471
550
class SmartClientMedium(SmartMedium):
472
551
    """Smart client is a medium for sending smart protocol requests over."""
473
552
 
482
561
        # _remote_version_is_before tracks the bzr version the remote side
483
562
        # can be based on what we've seen so far.
484
563
        self._remote_version_is_before = None
 
564
        # Install debug hook function if debug flag is set.
 
565
        if 'hpss' in debug.debug_flags:
 
566
            global _debug_counter
 
567
            if _debug_counter is None:
 
568
                _debug_counter = _DebugCounter()
 
569
            _debug_counter.track(self)
485
570
 
486
571
    def _is_remote_before(self, version_tuple):
487
572
        """Is it possible the remote side supports RPCs for a given version?
512
597
        """
513
598
        if (self._remote_version_is_before is not None and
514
599
            version_tuple > self._remote_version_is_before):
 
600
            # We have been told that the remote side is older than some version
 
601
            # which is newer than a previously supplied older-than version.
 
602
            # This indicates that some smart verb call is not guarded
 
603
            # appropriately (it should simply not have been tried).
515
604
            raise AssertionError(
516
605
                "_remember_remote_is_before(%r) called, but "
517
606
                "_remember_remote_is_before(%r) was called previously."
555
644
 
556
645
    def disconnect(self):
557
646
        """If this medium maintains a persistent connection, close it.
558
 
        
 
647
 
559
648
        The default implementation does nothing.
560
649
        """
561
 
        
 
650
 
562
651
    def remote_path_from_transport(self, transport):
563
652
        """Convert transport into a path suitable for using in a request.
564
 
        
 
653
 
565
654
        Note that the resulting remote path doesn't encode the host name or
566
655
        anything but path, so it is only safe to use it in requests sent over
567
656
        the medium from the matching transport.
595
684
 
596
685
    def _flush(self):
597
686
        """Flush the output stream.
598
 
        
 
687
 
599
688
        This method is used by the SmartClientStreamMediumRequest to ensure that
600
689
        all data for a request is sent, to avoid long timeouts or deadlocks.
601
690
        """
612
701
 
613
702
class SmartSimplePipesClientMedium(SmartClientStreamMedium):
614
703
    """A client medium using simple pipes.
615
 
    
 
704
 
616
705
    This client does not manage the pipes: it assumes they will always be open.
617
706
    """
618
707
 
624
713
    def _accept_bytes(self, bytes):
625
714
        """See SmartClientStreamMedium.accept_bytes."""
626
715
        self._writeable_pipe.write(bytes)
 
716
        self._report_activity(len(bytes), 'write')
627
717
 
628
718
    def _flush(self):
629
719
        """See SmartClientStreamMedium._flush()."""
631
721
 
632
722
    def _read_bytes(self, count):
633
723
        """See SmartClientStreamMedium._read_bytes."""
634
 
        return self._readable_pipe.read(count)
 
724
        bytes = self._readable_pipe.read(count)
 
725
        self._report_activity(len(bytes), 'read')
 
726
        return bytes
635
727
 
636
728
 
637
729
class SmartSSHClientMedium(SmartClientStreamMedium):
638
730
    """A client medium using SSH."""
639
 
    
 
731
 
640
732
    def __init__(self, host, port=None, username=None, password=None,
641
733
            base=None, vendor=None, bzr_remote_path=None):
642
734
        """Creates a client that will connect on the first use.
643
 
        
 
735
 
644
736
        :param vendor: An optional override for the ssh vendor to use. See
645
737
            bzrlib.transport.ssh for details on ssh vendors.
646
738
        """
647
 
        SmartClientStreamMedium.__init__(self, base)
648
739
        self._connected = False
649
740
        self._host = host
650
741
        self._password = password
651
742
        self._port = port
652
743
        self._username = username
 
744
        # SmartClientStreamMedium stores the repr of this object in its
 
745
        # _DebugCounter so we have to store all the values used in our repr
 
746
        # method before calling the super init.
 
747
        SmartClientStreamMedium.__init__(self, base)
653
748
        self._read_from = None
654
749
        self._ssh_connection = None
655
750
        self._vendor = vendor
656
751
        self._write_to = None
657
752
        self._bzr_remote_path = bzr_remote_path
658
 
        if self._bzr_remote_path is None:
659
 
            symbol_versioning.warn(
660
 
                'bzr_remote_path is required as of bzr 0.92',
661
 
                DeprecationWarning, stacklevel=2)
662
 
            self._bzr_remote_path = os.environ.get('BZR_REMOTE_PATH', 'bzr')
 
753
        # for the benefit of progress making a short description of this
 
754
        # transport
 
755
        self._scheme = 'bzr+ssh'
 
756
 
 
757
    def __repr__(self):
 
758
        return "%s(connected=%r, username=%r, host=%r, port=%r)" % (
 
759
            self.__class__.__name__,
 
760
            self._connected,
 
761
            self._username,
 
762
            self._host,
 
763
            self._port)
663
764
 
664
765
    def _accept_bytes(self, bytes):
665
766
        """See SmartClientStreamMedium.accept_bytes."""
666
767
        self._ensure_connection()
667
768
        self._write_to.write(bytes)
 
769
        self._report_activity(len(bytes), 'write')
668
770
 
669
771
    def disconnect(self):
670
772
        """See SmartClientMedium.disconnect()."""
700
802
        if not self._connected:
701
803
            raise errors.MediumNotConnected(self)
702
804
        bytes_to_read = min(count, _MAX_READ_SIZE)
703
 
        return self._read_from.read(bytes_to_read)
 
805
        bytes = self._read_from.read(bytes_to_read)
 
806
        self._report_activity(len(bytes), 'read')
 
807
        return bytes
704
808
 
705
809
 
706
810
# Port 4155 is the default port for bzr://, registered with IANA.
707
 
BZR_DEFAULT_INTERFACE = '0.0.0.0'
 
811
BZR_DEFAULT_INTERFACE = None
708
812
BZR_DEFAULT_PORT = 4155
709
813
 
710
814
 
711
815
class SmartTCPClientMedium(SmartClientStreamMedium):
712
816
    """A client medium using TCP."""
713
 
    
 
817
 
714
818
    def __init__(self, host, port, base):
715
819
        """Creates a client that will connect on the first use."""
716
820
        SmartClientStreamMedium.__init__(self, base)
722
826
    def _accept_bytes(self, bytes):
723
827
        """See SmartClientMedium.accept_bytes."""
724
828
        self._ensure_connection()
725
 
        osutils.send_all(self._socket, bytes)
 
829
        osutils.send_all(self._socket, bytes, self._report_activity)
726
830
 
727
831
    def disconnect(self):
728
832
        """See SmartClientMedium.disconnect()."""
736
840
        """Connect this medium if not already connected."""
737
841
        if self._connected:
738
842
            return
739
 
        self._socket = socket.socket()
740
 
        self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
741
843
        if self._port is None:
742
844
            port = BZR_DEFAULT_PORT
743
845
        else:
744
846
            port = int(self._port)
745
847
        try:
746
 
            self._socket.connect((self._host, port))
747
 
        except socket.error, err:
 
848
            sockaddrs = socket.getaddrinfo(self._host, port, socket.AF_UNSPEC,
 
849
                socket.SOCK_STREAM, 0, 0)
 
850
        except socket.gaierror, (err_num, err_msg):
 
851
            raise errors.ConnectionError("failed to lookup %s:%d: %s" %
 
852
                    (self._host, port, err_msg))
 
853
        # Initialize err in case there are no addresses returned:
 
854
        err = socket.error("no address found for %s" % self._host)
 
855
        for (family, socktype, proto, canonname, sockaddr) in sockaddrs:
 
856
            try:
 
857
                self._socket = socket.socket(family, socktype, proto)
 
858
                self._socket.setsockopt(socket.IPPROTO_TCP,
 
859
                                        socket.TCP_NODELAY, 1)
 
860
                self._socket.connect(sockaddr)
 
861
            except socket.error, err:
 
862
                if self._socket is not None:
 
863
                    self._socket.close()
 
864
                self._socket = None
 
865
                continue
 
866
            break
 
867
        if self._socket is None:
748
868
            # socket errors either have a (string) or (errno, string) as their
749
869
            # args.
750
870
            if type(err.args) is str:
757
877
 
758
878
    def _flush(self):
759
879
        """See SmartClientStreamMedium._flush().
760
 
        
761
 
        For TCP we do no flushing. We may want to turn off TCP_NODELAY and 
 
880
 
 
881
        For TCP we do no flushing. We may want to turn off TCP_NODELAY and
762
882
        add a means to do a flush, but that can be done in the future.
763
883
        """
764
884
 
766
886
        """See SmartClientMedium.read_bytes."""
767
887
        if not self._connected:
768
888
            raise errors.MediumNotConnected(self)
769
 
        # We ignore the desired_count because on sockets it's more efficient to
770
 
        # read large chunks (of _MAX_READ_SIZE bytes) at a time.
771
 
        return self._socket.recv(_MAX_READ_SIZE)
 
889
        return _read_bytes_from_socket(
 
890
            self._socket.recv, count, self._report_activity)
772
891
 
773
892
 
774
893
class SmartClientStreamMediumRequest(SmartClientMediumRequest):
787
906
 
788
907
    def _accept_bytes(self, bytes):
789
908
        """See SmartClientMediumRequest._accept_bytes.
790
 
        
 
909
 
791
910
        This forwards to self._medium._accept_bytes because we are operating
792
911
        on the mediums stream.
793
912
        """
796
915
    def _finished_reading(self):
797
916
        """See SmartClientMediumRequest._finished_reading.
798
917
 
799
 
        This clears the _current_request on self._medium to allow a new 
 
918
        This clears the _current_request on self._medium to allow a new
800
919
        request to be created.
801
920
        """
802
921
        if self._medium._current_request is not self:
803
922
            raise AssertionError()
804
923
        self._medium._current_request = None
805
 
        
 
924
 
806
925
    def _finished_writing(self):
807
926
        """See SmartClientMediumRequest._finished_writing.
808
927
 
810
929
        """
811
930
        self._medium._flush()
812
931
 
 
932
 
 
933
def _read_bytes_from_socket(sock, desired_count, report_activity):
 
934
    # We ignore the desired_count because on sockets it's more efficient to
 
935
    # read large chunks (of _MAX_READ_SIZE bytes) at a time.
 
936
    try:
 
937
        bytes = osutils.until_no_eintr(sock, _MAX_READ_SIZE)
 
938
    except socket.error, e:
 
939
        if len(e.args) and e.args[0] in (errno.ECONNRESET, 10054):
 
940
            # The connection was closed by the other side.  Callers expect an
 
941
            # empty string to signal end-of-stream.
 
942
            bytes = ''
 
943
        else:
 
944
            raise
 
945
    else:
 
946
        report_activity(len(bytes), 'read')
 
947
    return bytes
 
948