/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-02-07 06:59:48 UTC
  • mfrom: (3213.1.8 request-body-recovery)
  • Revision ID: pqm@pqm.ubuntu.com-20080207065948-pjxwy4z6ljrpugj8
(andrew,
        #185394) Disconnect and reconnect the smart medium after getting
        unknown

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    zero_ninetyone,
43
43
    )
44
44
from bzrlib.revision import NULL_REVISION
45
 
from bzrlib.trace import mutter, note
 
45
from bzrlib.trace import mutter, note, warning
46
46
 
47
47
# Note: RemoteBzrDirFormat is in bzrdir.py
48
48
 
777
777
        """See bzrlib.Graph.get_parent_map()."""
778
778
        # Hack to build up the caching logic.
779
779
        ancestry = self._parents_map
780
 
        missing_revisions = set(key for key in keys if key not in ancestry)
 
780
        if ancestry is None:
 
781
            # Repository is not locked, so there's no cache.
 
782
            missing_revisions = set(keys)
 
783
            ancestry = {}
 
784
        else:
 
785
            missing_revisions = set(key for key in keys if key not in ancestry)
781
786
        if missing_revisions:
782
787
            parent_map = self._get_parent_map(missing_revisions)
783
788
            if 'hpss' in debug.debug_flags:
784
789
                mutter('retransmitted revisions: %d of %d',
785
 
                        len(set(self._parents_map).intersection(parent_map)),
 
790
                        len(set(ancestry).intersection(parent_map)),
786
791
                        len(parent_map))
787
 
            self._parents_map.update(parent_map)
 
792
            ancestry.update(parent_map)
788
793
        present_keys = [k for k in keys if k in ancestry]
789
794
        if 'hpss' in debug.debug_flags:
790
795
            self._requested_parents.update(present_keys)
791
796
            mutter('Current RemoteRepository graph hit rate: %d%%',
792
 
                100.0 * len(self._requested_parents) / len(self._parents_map))
 
797
                100.0 * len(self._requested_parents) / len(ancestry))
793
798
        return dict((k, ancestry[k]) for k in present_keys)
794
799
 
795
800
    def _response_is_unknown_method(self, response, verb):
812
817
 
813
818
    def _get_parent_map(self, keys):
814
819
        """Helper for get_parent_map that performs the RPC."""
 
820
        medium = self._client.get_smart_medium()
 
821
        if not medium._remote_is_at_least_1_2:
 
822
            # We already found out that the server can't understand
 
823
            # Repository.get_parent_map requests, so just fetch the whole
 
824
            # graph.
 
825
            return self.get_revision_graph()
 
826
 
815
827
        keys = set(keys)
816
828
        if NULL_REVISION in keys:
817
829
            keys.discard(NULL_REVISION)
831
843
        # TODO: Manage this incrementally to avoid covering the same path
832
844
        # repeatedly. (The server will have to on each request, but the less
833
845
        # work done the better).
834
 
        start_set = set(self._parents_map)
 
846
        parents_map = self._parents_map
 
847
        if parents_map is None:
 
848
            # Repository is not locked, so there's no cache.
 
849
            parents_map = {}
 
850
        start_set = set(parents_map)
835
851
        result_parents = set()
836
 
        for parents in self._parents_map.itervalues():
 
852
        for parents in parents_map.itervalues():
837
853
            result_parents.update(parents)
838
854
        stop_keys = result_parents.difference(start_set)
839
855
        included_keys = start_set.intersection(result_parents)
840
856
        start_set.difference_update(included_keys)
841
 
        recipe = (start_set, stop_keys, len(self._parents_map))
 
857
        recipe = (start_set, stop_keys, len(parents_map))
842
858
        body = self._serialise_search_recipe(recipe)
843
859
        path = self.bzrdir._path_for_remote_call(self._client)
844
860
        for key in keys:
848
864
        response = self._client.call_with_body_bytes_expecting_body(
849
865
            verb, args, self._serialise_search_recipe(recipe))
850
866
        if self._response_is_unknown_method(response, verb):
851
 
            # Server that does not support this method, get the whole graph.
852
 
            response = self._client.call_expecting_body(
853
 
                'Repository.get_revision_graph', path, '')
854
 
            if response[0][0] not in ['ok', 'nosuchrevision']:
855
 
                reponse[1].cancel_read_body()
856
 
                raise errors.UnexpectedSmartServerResponse(response[0])
 
867
            # Server does not support this method, so get the whole graph.
 
868
            # Worse, we have to force a disconnection, because the server now
 
869
            # doesn't realise it has a body on the wire to consume, so the
 
870
            # only way to recover is to abandon the connection.
 
871
            warning(
 
872
                'Server is too old for fast get_parent_map, reconnecting.  '
 
873
                '(Upgrade the server to Bazaar 1.2 to avoid this)')
 
874
            medium.disconnect()
 
875
            # To avoid having to disconnect repeatedly, we keep track of the
 
876
            # fact the server doesn't understand remote methods added in 1.2.
 
877
            medium._remote_is_at_least_1_2 = False
 
878
            return self.get_revision_graph()
857
879
        elif response[0][0] not in ['ok']:
858
880
            reponse[1].cancel_read_body()
859
881
            raise errors.UnexpectedSmartServerResponse(response[0])
1009
1031
        return self._real_repository.has_signature_for_revision_id(revision_id)
1010
1032
 
1011
1033
    def get_data_stream_for_search(self, search):
 
1034
        medium = self._client.get_smart_medium()
 
1035
        if not medium._remote_is_at_least_1_2:
 
1036
            self._ensure_real()
 
1037
            return self._real_repository.get_data_stream_for_search(search)
1012
1038
        REQUEST_NAME = 'Repository.stream_revisions_chunked'
1013
1039
        path = self.bzrdir._path_for_remote_call(self._client)
1014
1040
        body = self._serialise_search_recipe(search.get_recipe())
1015
1041
        response, protocol = self._client.call_with_body_bytes_expecting_body(
1016
1042
            REQUEST_NAME, (path,), body)
1017
1043
 
 
1044
        if self._response_is_unknown_method((response, protocol), REQUEST_NAME):
 
1045
            # Server does not support this method, so fall back to VFS.
 
1046
            # Worse, we have to force a disconnection, because the server now
 
1047
            # doesn't realise it has a body on the wire to consume, so the
 
1048
            # only way to recover is to abandon the connection.
 
1049
            warning(
 
1050
                'Server is too old for streaming pull, reconnecting.  '
 
1051
                '(Upgrade the server to Bazaar 1.2 to avoid this)')
 
1052
            medium.disconnect()
 
1053
            # To avoid having to disconnect repeatedly, we keep track of the
 
1054
            # fact the server doesn't understand this remote method.
 
1055
            medium._remote_is_at_least_1_2 = False
 
1056
            self._ensure_real()
 
1057
            return self._real_repository.get_data_stream_for_search(search)
 
1058
 
1018
1059
        if response == ('ok',):
1019
1060
            return self._deserialise_stream(protocol)
1020
1061
        if response == ('NoSuchRevision', ):
1021
1062
            # We cannot easily identify the revision that is missing in this
1022
1063
            # situation without doing much more network IO. For now, bail.
1023
1064
            raise NoSuchRevision(self, "unknown")
1024
 
        elif (response == ('error', "Generic bzr smart protocol error: "
1025
 
                "bad request '%s'" % REQUEST_NAME) or
1026
 
              response == ('error', "Generic bzr smart protocol error: "
1027
 
                "bad request u'%s'" % REQUEST_NAME)):
1028
 
            protocol.cancel_read_body()
1029
 
            self._ensure_real()
1030
 
            return self._real_repository.get_data_stream_for_search(search)
1031
1065
        else:
1032
1066
            raise errors.UnexpectedSmartServerResponse(response)
1033
1067