~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/repository.py

merge 2.0 branch rev 4647

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import bz2
20
20
import os
21
21
import Queue
22
 
import struct
23
22
import sys
24
23
import tarfile
25
24
import tempfile
31
30
    graph,
32
31
    osutils,
33
32
    pack,
 
33
    versionedfile,
34
34
    )
35
35
from bzrlib.bzrdir import BzrDir
36
36
from bzrlib.smart.request import (
40
40
    )
41
41
from bzrlib.repository import _strip_NULL_ghosts, network_format_registry
42
42
from bzrlib import revision as _mod_revision
43
 
from bzrlib.versionedfile import NetworkRecordStream, record_to_fulltext_bytes
 
43
from bzrlib.versionedfile import (
 
44
    NetworkRecordStream,
 
45
    record_to_fulltext_bytes,
 
46
    )
44
47
 
45
48
 
46
49
class SmartServerRepositoryRequest(SmartServerRequest):
284
287
        return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
285
288
 
286
289
 
 
290
class SmartServerRepositoryGetRevIdForRevno(SmartServerRepositoryReadLocked):
 
291
 
 
292
    def do_readlocked_repository_request(self, repository, revno,
 
293
            known_pair):
 
294
        """Find the revid for a given revno, given a known revno/revid pair.
 
295
        
 
296
        New in 1.17.
 
297
        """
 
298
        try:
 
299
            found_flag, result = repository.get_rev_id_for_revno(revno, known_pair)
 
300
        except errors.RevisionNotPresent, err:
 
301
            if err.revision_id != known_pair[1]:
 
302
                raise AssertionError(
 
303
                    'get_rev_id_for_revno raised RevisionNotPresent for '
 
304
                    'non-initial revision: ' + err.revision_id)
 
305
            return FailedSmartServerResponse(
 
306
                ('nosuchrevision', err.revision_id))
 
307
        if found_flag:
 
308
            return SuccessfulSmartServerResponse(('ok', result))
 
309
        else:
 
310
            earliest_revno, earliest_revid = result
 
311
            return SuccessfulSmartServerResponse(
 
312
                ('history-incomplete', earliest_revno, earliest_revid))
 
313
 
 
314
 
287
315
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
288
316
 
289
317
    def do_repository_request(self, repository, revision_id):
390
418
            repository.
391
419
        """
392
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'))
393
424
        return None # Signal that we want a body.
394
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
 
395
457
    def do_body(self, body_bytes):
396
458
        repository = self._repository
397
459
        repository.lock_read()
427
489
            repository.unlock()
428
490
 
429
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
 
430
499
def _stream_to_byte_stream(stream, src_format):
431
500
    """Convert a record stream to a self delimited byte stream."""
432
501
    pack_writer = pack.ContainerSerialiser()
436
505
        for record in substream:
437
506
            if record.storage_kind in ('chunked', 'fulltext'):
438
507
                serialised = record_to_fulltext_bytes(record)
 
508
            elif record.storage_kind == 'inventory-delta':
 
509
                serialised = record_to_inventory_delta_bytes(record)
439
510
            elif record.storage_kind == 'absent':
440
511
                raise ValueError("Absent factory for %s" % (record.key,))
441
512
            else:
626
697
            return SuccessfulSmartServerResponse(('ok', ))
627
698
 
628
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
 
629
717
class SmartServerRepositoryInsertStream(SmartServerRepositoryInsertStreamLocked):
630
718
    """Insert a record stream from a RemoteSink into an unlocked repository.
631
719