/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/transport/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-10-04 07:12:14 UTC
  • mfrom: (2745.5.6 transport-get-file)
  • Revision ID: pqm@pqm.ubuntu.com-20071004071214-i0icltanhq59qtwt
(robertc) Transport improvements from packs: new trace+ transport, and readv adjust_for_latency feature, as well as test harness cleanup. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
99
99
                modules.add(factory._module_name)
100
100
            else:
101
101
                modules.add(factory._obj.__module__)
102
 
    # Add chroot directly, because there is not handler registered for it.
 
102
    # Add chroot directly, because there is no handler registered for it.
103
103
    modules.add('bzrlib.transport.chroot')
104
104
    result = list(modules)
105
105
    result.sort()
125
125
        self.get(key).insert(0, registry._ObjectGetter(obj))
126
126
 
127
127
    def register_lazy_transport_provider(self, key, module_name, member_name):
128
 
        self.get(key).insert(0, 
 
128
        self.get(key).insert(0,
129
129
                registry._LazyObjectGetter(module_name, member_name))
130
130
 
131
131
    def register_transport(self, key, help=None, default_port=None):
143
143
            return None
144
144
 
145
145
 
146
 
transport_list_registry = TransportListRegistry( )
 
146
transport_list_registry = TransportListRegistry()
147
147
 
148
148
 
149
149
def register_transport_proto(prefix, help=None, info=None, default_port=None):
642
642
        """
643
643
        raise errors.NoSmartMedium(self)
644
644
 
645
 
    def readv(self, relpath, offsets):
646
 
        """Get parts of the file at the given relative path.
647
 
 
648
 
        :offsets: A list of (offset, size) tuples.
 
645
    def readv(self, relpath, offsets, adjust_for_latency=False,
 
646
        upper_limit=None):
 
647
        """Get parts of the file at the given relative path.
 
648
 
 
649
        :param relpath: The path to read data from.
 
650
        :param offsets: A list of (offset, size) tuples.
 
651
        :param adjust_for_latency: Adjust the requested offsets to accomdate
 
652
            transport latency. This may re-order the offsets, expand them to
 
653
            grab adjacent data when there is likely a high cost to requesting
 
654
            data relative to delivering it.
 
655
        :param upper_limit: When adjust_for_latency is True setting upper_limit
 
656
            allows the caller to tell the transport about the length of the
 
657
            file, so that requests are not issued for ranges beyond the end of
 
658
            the file. This matters because some servers and/or transports error
 
659
            in such a case rather than just satisfying the available ranges.
 
660
            upper_limit should always be provided when adjust_for_latency is
 
661
            True, and should be the size of the file in bytes.
 
662
        :return: A list or generator of (offset, data) tuples
 
663
        """
 
664
        if adjust_for_latency:
 
665
            offsets = sorted(offsets)
 
666
            # short circuit empty requests
 
667
            if len(offsets) == 0:
 
668
                def empty_yielder():
 
669
                    # Quick thunk to stop this function becoming a generator
 
670
                    # itself, rather we return a generator that has nothing to
 
671
                    # yield.
 
672
                    if False:
 
673
                        yield None
 
674
                return empty_yielder()
 
675
            # expand by page size at either end
 
676
            expansion = self.recommended_page_size()
 
677
            reduction = expansion / 2
 
678
            new_offsets = []
 
679
            for offset, length in offsets:
 
680
                new_offset = offset - reduction
 
681
                new_length = length + expansion
 
682
                if new_offset < 0:
 
683
                    # don't ask for anything < 0
 
684
                    new_length -= new_offset
 
685
                    new_offset = 0
 
686
                if (upper_limit is not None and
 
687
                    new_offset + new_length > upper_limit):
 
688
                    new_length = upper_limit - new_offset
 
689
                new_offsets.append((new_offset, new_length))
 
690
            # combine the expanded offsets
 
691
            offsets = []
 
692
            current_offset, current_length = new_offsets[0]
 
693
            current_finish = current_length + current_offset
 
694
            for offset, length in new_offsets[1:]:
 
695
                if offset > current_finish:
 
696
                    offsets.append((current_offset, current_length))
 
697
                    current_offset = offset
 
698
                    current_length = length
 
699
                    continue
 
700
                finish = offset + length
 
701
                if finish > current_finish:
 
702
                    current_finish = finish
 
703
            offsets.append((current_offset, current_length))
 
704
        return self._readv(relpath, offsets)
 
705
 
 
706
    def _readv(self, relpath, offsets):
 
707
        """Get parts of the file at the given relative path.
 
708
 
 
709
        :param relpath: The path to read.
 
710
        :param offsets: A list of (offset, size) tuples.
649
711
        :return: A list or generator of (offset, data) tuples
650
712
        """
651
713
        if not offsets:
1609
1671
        raise NotImplementedError
1610
1672
 
1611
1673
 
1612
 
class TransportLogger(object):
1613
 
    """Adapt a transport to get clear logging data on api calls.
1614
 
    
1615
 
    Feel free to extend to log whatever calls are of interest.
1616
 
    """
1617
 
 
1618
 
    def __init__(self, adapted):
1619
 
        self._adapted = adapted
1620
 
        self._calls = []
1621
 
 
1622
 
    def get(self, name):
1623
 
        self._calls.append((name,))
1624
 
        return self._adapted.get(name)
1625
 
 
1626
 
    def __getattr__(self, name):
1627
 
        """Thunk all undefined access through to self._adapted."""
1628
 
        # raise AttributeError, name 
1629
 
        return getattr(self._adapted, name)
1630
 
 
1631
 
    def readv(self, name, offsets):
1632
 
        self._calls.append((name, offsets))
1633
 
        return self._adapted.readv(name, offsets)
1634
 
 
1635
 
 
1636
1674
# None is the default transport, for things with no url scheme
1637
1675
register_transport_proto('file://',
1638
1676
            help="Access using the standard filesystem (default)")
1689
1727
 
1690
1728
register_transport_proto('memory://')
1691
1729
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
 
1730
 
 
1731
# chroots cannot be implicitly accessed, they must be explicitly created:
1692
1732
register_transport_proto('chroot+')
1693
1733
 
1694
1734
register_transport_proto('readonly+',
1699
1739
register_transport_proto('fakenfs+')
1700
1740
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
1701
1741
 
 
1742
register_transport_proto('trace+')
 
1743
register_lazy_transport('trace+', 'bzrlib.transport.trace', 'TransportTraceDecorator')
 
1744
 
1702
1745
register_transport_proto('unlistable+')
1703
1746
register_lazy_transport('unlistable+', 'bzrlib.transport.unlistable', 'UnlistableTransportDecorator')
1704
1747