~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

  • Committer: Martin Pool
  • Date: 2006-03-10 06:29:53 UTC
  • mfrom: (1608 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1611.
  • Revision ID: mbp@sourcefrog.net-20060310062953-bc1c7ade75c89a7a
[merge] bzr.dev; pycurl not updated for readv yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
"""
28
28
 
29
29
import errno
 
30
from collections import deque
30
31
from copy import deepcopy
31
32
from stat import *
32
33
import sys
209
210
                        as a single parameter.
210
211
        """
211
212
        total = self._get_total(multi)
 
213
        result = []
212
214
        count = 0
213
215
        for entry in multi:
214
216
            self._update_pb(pb, msg, count, total)
215
217
            if expand:
216
 
                func(*entry)
 
218
                result.append(func(*entry))
217
219
            else:
218
 
                func(entry)
 
220
                result.append(func(entry))
219
221
            count += 1
220
 
        return count
 
222
        return tuple(result)
221
223
 
222
224
    def abspath(self, relpath):
223
225
        """Return the full url to the given relative path.
247
249
        """Does the file relpath exist?
248
250
        
249
251
        Note that some transports MAY allow querying on directories, but this
250
 
        is not part of the protocol.
 
252
        is not part of the protocol.  In other words, the results of 
 
253
        t.has("a_directory_name") are undefined."
251
254
        """
252
255
        raise NotImplementedError(self.has)
253
256
 
287
290
        """
288
291
        raise NotImplementedError(self.get)
289
292
 
 
293
    def readv(self, relpath, offsets):
 
294
        """Get parts of the file at the given relative path.
 
295
 
 
296
        :offsets: A list of (offset, size) tuples.
 
297
        :return: A list or generator of (offset, data) tuples
 
298
        """
 
299
        def do_combined_read(combined_offsets):
 
300
            total_size = 0
 
301
            for offset, size in combined_offsets:
 
302
                total_size += size
 
303
            mutter('readv coalesced %d reads.', len(combined_offsets))
 
304
            offset = combined_offsets[0][0]
 
305
            fp.seek(offset)
 
306
            data = fp.read(total_size)
 
307
            pos = 0
 
308
            for offset, size in combined_offsets:
 
309
                yield offset, data[pos:pos + size]
 
310
                pos += size
 
311
 
 
312
        if not len(offsets):
 
313
            return
 
314
        fp = self.get(relpath)
 
315
        pending_offsets = deque(offsets)
 
316
        combined_offsets = []
 
317
        while len(pending_offsets):
 
318
            offset, size = pending_offsets.popleft()
 
319
            if not combined_offsets:
 
320
                combined_offsets = [[offset, size]]
 
321
            else:
 
322
                if (len (combined_offsets) < 50 and
 
323
                    combined_offsets[-1][0] + combined_offsets[-1][1] == offset):
 
324
                    # combatible offset:
 
325
                    combined_offsets.append([offset, size])
 
326
                else:
 
327
                    # incompatible, or over the threshold issue a read and yield
 
328
                    pending_offsets.appendleft((offset, size))
 
329
                    for result in do_combined_read(combined_offsets):
 
330
                        yield result
 
331
                    combined_offsets = []
 
332
        # whatever is left is a single coalesced request
 
333
        if len(combined_offsets):
 
334
            for result in do_combined_read(combined_offsets):
 
335
                yield result
 
336
 
290
337
    def get_multi(self, relpaths, pb=None):
291
338
        """Get a list of file-like objects, one for each entry in relpaths.
292
339
 
324
371
        """
325
372
        def put(path, f):
326
373
            self.put(path, f, mode=mode)
327
 
        return self._iterate_over(files, put, pb, 'put', expand=True)
 
374
        return len(self._iterate_over(files, put, pb, 'put', expand=True))
328
375
 
329
376
    def mkdir(self, relpath, mode=None):
330
377
        """Create a directory at the given path."""
334
381
        """Create a group of directories"""
335
382
        def mkdir(path):
336
383
            self.mkdir(path, mode=mode)
337
 
        return self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False)
 
384
        return len(self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False))
338
385
 
339
386
    def append(self, relpath, f):
340
387
        """Append the text in the file-like or string object to 
341
388
        the supplied location.
 
389
 
 
390
        returns the length of f before the content was written to it.
342
391
        """
343
392
        raise NotImplementedError(self.append)
344
393
 
380
429
        def copy_entry(path):
381
430
            other.put(path, self.get(path), mode=mode)
382
431
 
383
 
        return self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False)
 
432
        return len(self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False))
384
433
 
385
434
    def copy_tree(self, from_relpath, to_relpath):
386
435
        """Copy a subtree from one relpath to another.
675
724
                # from running this test
676
725
                pass
677
726
        return result
 
727
 
 
728
 
 
729
class TransportLogger(object):
 
730
    """Adapt a transport to get clear logging data on api calls.
 
731
    
 
732
    Feel free to extend to log whatever calls are of interest.
 
733
    """
 
734
 
 
735
    def __init__(self, adapted):
 
736
        self._adapted = adapted
 
737
        self._calls = []
 
738
 
 
739
    def get(self, name):
 
740
        self._calls.append((name,))
 
741
        return self._adapted.get(name)
 
742
 
 
743
    def __getattr__(self, name):
 
744
        """Thunk all undefined access through to self._adapted."""
 
745
        # raise AttributeError, name 
 
746
        return getattr(self._adapted, name)
 
747
 
 
748
    def readv(self, name, offsets):
 
749
        self._calls.append((name, offsets))
 
750
        return self._adapted.readv(name, offsets)
678
751
        
679
752
 
680
753
# None is the default transport, for things with no url scheme
682
755
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
683
756
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
684
757
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
685
 
                        'HttpTransport')
 
758
                        'HttpTransport_urllib')
686
759
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
687
 
                        'HttpTransport')
688
 
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl', 
689
 
                        'PyCurlTransport')
690
 
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl', 
691
 
                        'PyCurlTransport')
692
 
register_lazy_transport('http://', 'bzrlib.transport.http._urllib', 'HttpTransport')
693
 
register_lazy_transport('https://', 'bzrlib.transport.http._urllib', 'HttpTransport')
 
760
                        'HttpTransport_urllib')
 
761
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
 
762
                        'PyCurlTransport')
 
763
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
 
764
                        'PyCurlTransport')
 
765
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
 
766
                        'HttpTransport_urllib')
 
767
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
 
768
                        'HttpTransport_urllib')
694
769
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
695
770
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
696
771
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')