~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/repository.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-08-14 05:49:27 UTC
  • mfrom: (4476.3.86 inventory-delta)
  • Revision ID: pqm@pqm.ubuntu.com-20090814054927-k0k18dn46ax4b91f
(andrew) Add inventory-delta streaming for cross-format fetch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    graph,
31
31
    osutils,
32
32
    pack,
 
33
    versionedfile,
33
34
    )
34
35
from bzrlib.bzrdir import BzrDir
35
36
from bzrlib.smart.request import (
39
40
    )
40
41
from bzrlib.repository import _strip_NULL_ghosts, network_format_registry
41
42
from bzrlib import revision as _mod_revision
42
 
from bzrlib.versionedfile import NetworkRecordStream, record_to_fulltext_bytes
 
43
from bzrlib.versionedfile import (
 
44
    NetworkRecordStream,
 
45
    record_to_fulltext_bytes,
 
46
    )
43
47
 
44
48
 
45
49
class SmartServerRepositoryRequest(SmartServerRequest):
414
418
            repository.
415
419
        """
416
420
        self._to_format = network_format_registry.get(to_network_name)
 
421
        if self._should_fake_unknown():
 
422
            return FailedSmartServerResponse(
 
423
                ('UnknownMethod', 'Repository.get_stream'))
417
424
        return None # Signal that we want a body.
418
425
 
 
426
    def _should_fake_unknown(self):
 
427
        """Return True if we should return UnknownMethod to the client.
 
428
        
 
429
        This is a workaround for bugs in pre-1.19 clients that claim to
 
430
        support receiving streams of CHK repositories.  The pre-1.19 client
 
431
        expects inventory records to be serialized in the format defined by
 
432
        to_network_name, but in pre-1.19 (at least) that format definition
 
433
        tries to use the xml5 serializer, which does not correctly handle
 
434
        rich-roots.  After 1.19 the client can also accept inventory-deltas
 
435
        (which avoids this issue), and those clients will use the
 
436
        Repository.get_stream_1.19 verb instead of this one.
 
437
        So: if this repository is CHK, and the to_format doesn't match,
 
438
        we should just fake an UnknownSmartMethod error so that the client
 
439
        will fallback to VFS, rather than sending it a stream we know it
 
440
        cannot handle.
 
441
        """
 
442
        from_format = self._repository._format
 
443
        to_format = self._to_format
 
444
        if not from_format.supports_chks:
 
445
            # Source not CHK: that's ok
 
446
            return False
 
447
        if (to_format.supports_chks and
 
448
            from_format.repository_class is to_format.repository_class and
 
449
            from_format._serializer == to_format._serializer):
 
450
            # Source is CHK, but target matches: that's ok
 
451
            # (e.g. 2a->2a, or CHK2->2a)
 
452
            return False
 
453
        # Source is CHK, and target is not CHK or incompatible CHK.  We can't
 
454
        # generate a compatible stream.
 
455
        return True
 
456
 
419
457
    def do_body(self, body_bytes):
420
458
        repository = self._repository
421
459
        repository.lock_read()
451
489
            repository.unlock()
452
490
 
453
491
 
 
492
class SmartServerRepositoryGetStream_1_19(SmartServerRepositoryGetStream):
 
493
 
 
494
    def _should_fake_unknown(self):
 
495
        """Returns False; we don't need to workaround bugs in 1.19+ clients."""
 
496
        return False
 
497
 
 
498
 
454
499
def _stream_to_byte_stream(stream, src_format):
455
500
    """Convert a record stream to a self delimited byte stream."""
456
501
    pack_writer = pack.ContainerSerialiser()
460
505
        for record in substream:
461
506
            if record.storage_kind in ('chunked', 'fulltext'):
462
507
                serialised = record_to_fulltext_bytes(record)
 
508
            elif record.storage_kind == 'inventory-delta':
 
509
                serialised = record_to_inventory_delta_bytes(record)
463
510
            elif record.storage_kind == 'absent':
464
511
                raise ValueError("Absent factory for %s" % (record.key,))
465
512
            else:
650
697
            return SuccessfulSmartServerResponse(('ok', ))
651
698
 
652
699
 
 
700
class SmartServerRepositoryInsertStream_1_19(SmartServerRepositoryInsertStreamLocked):
 
701
    """Insert a record stream from a RemoteSink into a repository.
 
702
 
 
703
    Same as SmartServerRepositoryInsertStreamLocked, except:
 
704
     - the lock token argument is optional
 
705
     - servers that implement this verb accept 'inventory-delta' records in the
 
706
       stream.
 
707
 
 
708
    New in 1.19.
 
709
    """
 
710
 
 
711
    def do_repository_request(self, repository, resume_tokens, lock_token=None):
 
712
        """StreamSink.insert_stream for a remote repository."""
 
713
        SmartServerRepositoryInsertStreamLocked.do_repository_request(
 
714
            self, repository, resume_tokens, lock_token)
 
715
 
 
716
 
653
717
class SmartServerRepositoryInsertStream(SmartServerRepositoryInsertStreamLocked):
654
718
    """Insert a record stream from a RemoteSink into an unlocked repository.
655
719