/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/smart/repository.py

  • Committer: Martin Pool
  • Date: 2008-02-06 00:41:04 UTC
  • mfrom: (3215 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3219.
  • Revision ID: mbp@sourcefrog.net-20080206004104-mxtn32habuhjq6b8
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 
25
25
from bzrlib import errors
26
26
from bzrlib.bzrdir import BzrDir
27
 
from bzrlib.pack import ContainerWriter
 
27
from bzrlib.pack import ContainerSerialiser
28
28
from bzrlib.smart.request import (
29
29
    FailedSmartServerResponse,
30
30
    SmartServerRequest,
31
31
    SuccessfulSmartServerResponse,
32
32
    )
 
33
from bzrlib import revision as _mod_revision
33
34
 
34
35
 
35
36
class SmartServerRepositoryRequest(SmartServerRequest):
47
48
        """
48
49
        transport = self._backing_transport.clone(path)
49
50
        bzrdir = BzrDir.open_from_transport(transport)
50
 
        repository = bzrdir.open_repository()
51
 
        return self.do_repository_request(repository, *args)
 
51
        # Save the repository for use with do_body.
 
52
        self._repository = bzrdir.open_repository()
 
53
        return self.do_repository_request(self._repository, *args)
 
54
 
 
55
    def do_repository_request(self, repository, *args):
 
56
        """Override to provide an implementation for a verb."""
 
57
        # No-op for verbs that take bodies (None as a result indicates a body
 
58
        # is expected)
 
59
        return None
 
60
 
 
61
 
 
62
class SmartServerRepositoryGetParentMap(SmartServerRepositoryRequest):
 
63
    
 
64
    def do_repository_request(self, repository, *revision_ids):
 
65
        repository.lock_read()
 
66
        try:
 
67
            return self._do_repository_request(repository, revision_ids)
 
68
        finally:
 
69
            repository.unlock()
 
70
 
 
71
    def _do_repository_request(self, repository, revision_ids):
 
72
        """Get parent details for some revisions.
 
73
        
 
74
        All the parents for revision_ids are returned. Additionally up to 64KB
 
75
        of additional parent data found by performing a breadth first search
 
76
        from revision_ids is returned.
 
77
 
 
78
        :param repository: The repository to query in.
 
79
        :param revision_ids: The utf8 encoded revision_id to answer for.
 
80
        :return: A smart server response where the body contains an utf8
 
81
            encoded flattened list of the parents of the revisions, (the same
 
82
            format as Repository.get_revision_graph).
 
83
        """
 
84
        lines = []
 
85
        repo_graph = repository.get_graph()
 
86
        result = {}
 
87
        queried_revs = set()
 
88
        size_so_far = 0
 
89
        next_revs = revision_ids
 
90
        first_loop_done = False
 
91
        while next_revs:
 
92
            queried_revs.update(next_revs)
 
93
            parent_map = repo_graph.get_parent_map(next_revs)
 
94
            next_revs = set()
 
95
            for revision_id, parents in parent_map.iteritems():
 
96
                # adjust for the wire
 
97
                if parents == (_mod_revision.NULL_REVISION,):
 
98
                    parents = ()
 
99
                # add parents to the result
 
100
                result[revision_id] = parents
 
101
                # prepare the next query
 
102
                next_revs.update(parents)
 
103
                # Approximate the serialized cost of this revision_id.
 
104
                size_so_far += 2 + len(revision_id) + sum(map(len, parents))
 
105
                # get all the directly asked for parents, and then flesh out to
 
106
                # 64K or so.
 
107
                if first_loop_done and size_so_far > 65000:
 
108
                    next_revs = set()
 
109
                    break
 
110
            # don't query things we've already queried
 
111
            next_revs.difference_update(queried_revs)
 
112
            first_loop_done = True
 
113
 
 
114
        for revision, parents in result.items():
 
115
            lines.append(' '.join((revision, ) + tuple(parents)))
 
116
 
 
117
        return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
52
118
 
53
119
 
54
120
class SmartServerRepositoryGetRevisionGraph(SmartServerRepositoryRequest):
248
314
 
249
315
 
250
316
class SmartServerRepositoryStreamKnitDataForRevisions(SmartServerRepositoryRequest):
 
317
    """Bzr <= 1.1 streaming pull, buffers all data on server."""
251
318
 
252
319
    def do_repository_request(self, repository, *revision_ids):
253
320
        repository.lock_read()
257
324
            repository.unlock()
258
325
 
259
326
    def _do_repository_request(self, repository, revision_ids):
260
 
        stream = repository.get_data_stream(revision_ids)
261
 
        filelike = StringIO()
262
 
        pack = ContainerWriter(filelike.write)
263
 
        pack.begin()
 
327
        stream = repository.get_data_stream_for_search(
 
328
            repository.revision_ids_to_search_result(set(revision_ids)))
 
329
        buffer = StringIO()
 
330
        pack = ContainerSerialiser()
 
331
        buffer.write(pack.begin())
264
332
        try:
265
333
            for name_tuple, bytes in stream:
266
 
                pack.add_bytes_record(bytes, [name_tuple])
 
334
                buffer.write(pack.bytes_record(bytes, [name_tuple]))
267
335
        except errors.RevisionNotPresent, e:
268
336
            return FailedSmartServerResponse(('NoSuchRevision', e.revision_id))
 
337
        buffer.write(pack.end())
 
338
        return SuccessfulSmartServerResponse(('ok',), buffer.getvalue())
 
339
 
 
340
 
 
341
class SmartServerRepositoryStreamRevisionsChunked(SmartServerRepositoryRequest):
 
342
    """Bzr 1.1+ streaming pull."""
 
343
 
 
344
    def do_body(self, body_bytes):
 
345
        lines = body_bytes.split('\n')
 
346
        start_keys = set(lines[0].split(' '))
 
347
        exclude_keys = set(lines[1].split(' '))
 
348
        revision_count = int(lines[2])
 
349
        repository = self._repository
 
350
        repository.lock_read()
 
351
        try:
 
352
            search = repository.get_graph()._make_breadth_first_searcher(
 
353
                start_keys)
 
354
            while True:
 
355
                try:
 
356
                    next_revs = search.next()
 
357
                except StopIteration:
 
358
                    break
 
359
                search.stop_searching_any(exclude_keys.intersection(next_revs))
 
360
            search_result = search.get_result()
 
361
            if search_result.get_recipe()[2] != revision_count:
 
362
                # we got back a different amount of data than expected, this
 
363
                # gets reported as NoSuchRevision, because less revisions
 
364
                # indicates missing revisions, and more should never happen as
 
365
                # the excludes list considers ghosts and ensures that ghost
 
366
                # filling races are not a problem.
 
367
                return FailedSmartServerResponse(('NoSuchRevision',))
 
368
            stream = repository.get_data_stream_for_search(search_result)
 
369
        except Exception:
 
370
            repository.unlock()
 
371
            raise
 
372
        return SuccessfulSmartServerResponse(('ok',),
 
373
            body_stream=self.body_stream(stream, repository))
 
374
 
 
375
    def body_stream(self, stream, repository):
 
376
        pack = ContainerSerialiser()
 
377
        yield pack.begin()
 
378
        try:
 
379
            for name_tuple, bytes in stream:
 
380
                yield pack.bytes_record(bytes, [name_tuple])
 
381
        except errors.RevisionNotPresent, e:
 
382
            # This shouldn't be able to happen, but as we don't buffer
 
383
            # everything it can in theory happen.
 
384
            yield FailedSmartServerResponse(('NoSuchRevision', e.revision_id))
 
385
        repository.unlock()
269
386
        pack.end()
270
 
        return SuccessfulSmartServerResponse(('ok',), filelike.getvalue())
271
387