~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: John Arbash Meinel
  • Date: 2008-10-04 14:10:13 UTC
  • mto: This revision was merged to the branch mainline in revision 3805.
  • Revision ID: john@arbash-meinel.com-20081004141013-yskxjlwtuy2k18ue
Playing around with expanding requests for btree index nodes into neighboring nodes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""Infrastructure for server-side request handlers.
18
 
 
19
 
Interesting module attributes:
20
 
    * The request_handlers registry maps verb names to SmartServerRequest
21
 
      classes.
22
 
    * The jail_info threading.local() object is used to prevent accidental
23
 
      opening of BzrDirs outside of the backing transport, or any other
24
 
      transports placed in jail_info.transports.  The jail_info is reset on
25
 
      every call into a request handler (which can happen an arbitrary number
26
 
      of times during a request).
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Basic server-side logic for dealing with requests.
 
18
 
 
19
**XXX**:
 
20
 
 
21
The class names are a little confusing: the protocol will instantiate a
 
22
SmartServerRequestHandler, whose dispatch_command method creates an instance of
 
23
a SmartServerRequest subclass.
 
24
 
 
25
The request_handlers registry tracks SmartServerRequest classes (rather than
 
26
SmartServerRequestHandler).
27
27
"""
28
28
 
29
 
# XXX: The class names are a little confusing: the protocol will instantiate a
30
 
# SmartServerRequestHandler, whose dispatch_command method creates an instance
31
 
# of a SmartServerRequest subclass.
32
 
 
33
 
 
34
 
import threading
 
29
import tempfile
35
30
 
36
31
from bzrlib import (
37
32
    bzrdir,
38
 
    debug,
39
33
    errors,
40
 
    osutils,
41
34
    registry,
42
35
    revision,
43
 
    trace,
44
36
    urlutils,
45
37
    )
46
38
from bzrlib.lazy_import import lazy_import
47
39
lazy_import(globals(), """
48
40
from bzrlib.bundle import serializer
49
 
 
50
 
import tempfile
51
 
import thread
52
41
""")
53
42
 
54
43
 
55
 
jail_info = threading.local()
56
 
jail_info.transports = None
57
 
 
58
 
 
59
 
def _install_hook():
60
 
    bzrdir.BzrDir.hooks.install_named_hook(
61
 
        'pre_open', _pre_open_hook, 'checking server jail')
62
 
 
63
 
 
64
 
def _pre_open_hook(transport):
65
 
    allowed_transports = getattr(jail_info, 'transports', None)
66
 
    if allowed_transports is None:
67
 
        return
68
 
    abspath = transport.base
69
 
    for allowed_transport in allowed_transports:
70
 
        try:
71
 
            allowed_transport.relpath(abspath)
72
 
        except errors.PathNotChild:
73
 
            continue
74
 
        else:
75
 
            return
76
 
    raise errors.JailBreak(abspath)
77
 
 
78
 
 
79
 
_install_hook()
80
 
 
81
 
 
82
44
class SmartServerRequest(object):
83
45
    """Base class for request handlers.
84
 
 
 
46
    
85
47
    To define a new request, subclass this class and override the `do` method
86
48
    (and if appropriate, `do_body` as well).  Request implementors should take
87
49
    care to call `translate_client_path` and `transport_from_client_path` as
90
52
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
91
53
    # *handler* is a different concept to the request.
92
54
 
93
 
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
 
55
    def __init__(self, backing_transport, root_client_path='/'):
94
56
        """Constructor.
95
57
 
96
58
        :param backing_transport: the base transport to be used when performing
100
62
            from the client.  Clients will not be able to refer to paths above
101
63
            this root.  If root_client_path is None, then no translation will
102
64
            be performed on client paths.  Default is '/'.
103
 
        :param jail_root: if specified, the root of the BzrDir.open jail to use
104
 
            instead of backing_transport.
105
65
        """
106
66
        self._backing_transport = backing_transport
107
 
        if jail_root is None:
108
 
            jail_root = backing_transport
109
 
        self._jail_root = jail_root
110
67
        if root_client_path is not None:
111
68
            if not root_client_path.startswith('/'):
112
69
                root_client_path = '/' + root_client_path
113
70
            if not root_client_path.endswith('/'):
114
71
                root_client_path += '/'
115
72
        self._root_client_path = root_client_path
116
 
        self._body_chunks = []
117
73
 
118
74
    def _check_enabled(self):
119
75
        """Raises DisabledMethod if this method is disabled."""
121
77
 
122
78
    def do(self, *args):
123
79
        """Mandatory extension point for SmartServerRequest subclasses.
124
 
 
 
80
        
125
81
        Subclasses must implement this.
126
 
 
 
82
        
127
83
        This should return a SmartServerResponse if this command expects to
128
84
        receive no body.
129
85
        """
135
91
        It will return a SmartServerResponse if the command does not expect a
136
92
        body.
137
93
 
138
 
        :param args: the arguments of the request.
 
94
        :param *args: the arguments of the request.
139
95
        """
140
96
        self._check_enabled()
141
97
        return self.do(*args)
144
100
        """Called if the client sends a body with the request.
145
101
 
146
102
        The do() method is still called, and must have returned None.
147
 
 
 
103
        
148
104
        Must return a SmartServerResponse.
149
105
        """
150
 
        if body_bytes != '':
151
 
            raise errors.SmartProtocolError('Request does not expect a body')
 
106
        raise NotImplementedError(self.do_body)
152
107
 
153
108
    def do_chunk(self, chunk_bytes):
154
109
        """Called with each body chunk if the request has a streamed body.
155
110
 
156
111
        The do() method is still called, and must have returned None.
157
112
        """
158
 
        self._body_chunks.append(chunk_bytes)
 
113
        raise NotImplementedError(self.do_chunk)
159
114
 
160
115
    def do_end(self):
161
116
        """Called when the end of the request has been received."""
162
 
        body_bytes = ''.join(self._body_chunks)
163
 
        self._body_chunks = None
164
 
        return self.do_body(body_bytes)
165
 
 
166
 
    def setup_jail(self):
167
 
        jail_info.transports = [self._jail_root]
168
 
 
169
 
    def teardown_jail(self):
170
 
        jail_info.transports = None
171
 
 
 
117
        pass
 
118
    
172
119
    def translate_client_path(self, client_path):
173
120
        """Translate a path received from a network client into a local
174
121
        relpath.
185
132
            return client_path
186
133
        if not client_path.startswith('/'):
187
134
            client_path = '/' + client_path
188
 
        if client_path + '/' == self._root_client_path:
189
 
            return '.'
190
135
        if client_path.startswith(self._root_client_path):
191
136
            path = client_path[len(self._root_client_path):]
192
137
            relpath = urlutils.joinpath('/', path)
193
138
            if not relpath.startswith('/'):
194
139
                raise ValueError(relpath)
195
 
            return urlutils.escape('.' + relpath)
 
140
            return '.' + relpath
196
141
        else:
197
142
            raise errors.PathNotChild(client_path, self._root_client_path)
198
143
 
209
154
 
210
155
class SmartServerResponse(object):
211
156
    """A response to a client request.
212
 
 
 
157
    
213
158
    This base class should not be used. Instead use
214
159
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
215
160
    """
259
204
 
260
205
class SmartServerRequestHandler(object):
261
206
    """Protocol logic for smart server.
262
 
 
 
207
    
263
208
    This doesn't handle serialization at all, it just processes requests and
264
209
    creates responses.
265
210
    """
274
219
    # TODO: Better way of representing the body for commands that take it,
275
220
    # and allow it to be streamed into the server.
276
221
 
277
 
    def __init__(self, backing_transport, commands, root_client_path,
278
 
        jail_root=None):
 
222
    def __init__(self, backing_transport, commands, root_client_path):
279
223
        """Constructor.
280
224
 
281
225
        :param backing_transport: a Transport to handle requests for.
285
229
        self._backing_transport = backing_transport
286
230
        self._root_client_path = root_client_path
287
231
        self._commands = commands
288
 
        if jail_root is None:
289
 
            jail_root = backing_transport
290
 
        self._jail_root = jail_root
 
232
        self._body_bytes = ''
291
233
        self.response = None
292
234
        self.finished_reading = False
293
235
        self._command = None
294
 
        if 'hpss' in debug.debug_flags:
295
 
            self._request_start_time = osutils.timer_func()
296
 
            self._thread_id = thread.get_ident()
297
 
 
298
 
    def _trace(self, action, message, extra_bytes=None, include_time=False):
299
 
        # It is a bit of a shame that this functionality overlaps with that of 
300
 
        # ProtocolThreeRequester._trace. However, there is enough difference
301
 
        # that just putting it in a helper doesn't help a lot. And some state
302
 
        # is taken from the instance.
303
 
        if include_time:
304
 
            t = '%5.3fs ' % (osutils.timer_func() - self._request_start_time)
305
 
        else:
306
 
            t = ''
307
 
        if extra_bytes is None:
308
 
            extra = ''
309
 
        else:
310
 
            extra = ' ' + repr(extra_bytes[:40])
311
 
            if len(extra) > 33:
312
 
                extra = extra[:29] + extra[-1] + '...'
313
 
        trace.mutter('%12s: [%s] %s%s%s'
314
 
                     % (action, self._thread_id, t, message, extra))
315
236
 
316
237
    def accept_body(self, bytes):
317
238
        """Accept body data."""
318
 
        if self._command is None:
319
 
            # no active command object, so ignore the event.
320
 
            return
321
 
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
322
 
        if 'hpss' in debug.debug_flags:
323
 
            self._trace('accept body',
324
 
                        '%d bytes' % (len(bytes),), bytes)
325
 
 
 
239
 
 
240
        # TODO: This should be overriden for each command that desired body data
 
241
        # to handle the right format of that data, i.e. plain bytes, a bundle,
 
242
        # etc.  The deserialisation into that format should be done in the
 
243
        # Protocol object.
 
244
 
 
245
        # default fallback is to accumulate bytes.
 
246
        self._body_bytes += bytes
 
247
        
326
248
    def end_of_body(self):
327
249
        """No more body data will be received."""
328
 
        self._run_handler_code(self._command.do_end, (), {})
 
250
        self._run_handler_code(self._command.do_body, (self._body_bytes,), {})
329
251
        # cannot read after this.
330
252
        self.finished_reading = True
331
 
        if 'hpss' in debug.debug_flags:
332
 
            self._trace('end of body', '', include_time=True)
 
253
 
 
254
    def dispatch_command(self, cmd, args):
 
255
        """Deprecated compatibility method.""" # XXX XXX
 
256
        try:
 
257
            command = self._commands.get(cmd)
 
258
        except LookupError:
 
259
            raise errors.UnknownSmartMethod(cmd)
 
260
        self._command = command(self._backing_transport, self._root_client_path)
 
261
        self._run_handler_code(self._command.execute, args, {})
333
262
 
334
263
    def _run_handler_code(self, callable, args, kwargs):
335
264
        """Run some handler specific code 'callable'.
351
280
        # XXX: most of this error conversion is VFS-related, and thus ought to
352
281
        # be in SmartServerVFSRequestHandler somewhere.
353
282
        try:
354
 
            self._command.setup_jail()
355
 
            try:
356
 
                return callable(*args, **kwargs)
357
 
            finally:
358
 
                self._command.teardown_jail()
359
 
        except (KeyboardInterrupt, SystemExit):
360
 
            raise
361
 
        except Exception, err:
362
 
            err_struct = _translate_error(err)
363
 
            return FailedSmartServerResponse(err_struct)
 
283
            return callable(*args, **kwargs)
 
284
        except errors.NoSuchFile, e:
 
285
            return FailedSmartServerResponse(('NoSuchFile', e.path))
 
286
        except errors.FileExists, e:
 
287
            return FailedSmartServerResponse(('FileExists', e.path))
 
288
        except errors.DirectoryNotEmpty, e:
 
289
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
 
290
        except errors.ShortReadvError, e:
 
291
            return FailedSmartServerResponse(('ShortReadvError',
 
292
                e.path, str(e.offset), str(e.length), str(e.actual)))
 
293
        except errors.UnstackableRepositoryFormat, e:
 
294
            return FailedSmartServerResponse(('UnstackableRepositoryFormat',
 
295
                str(e.format), e.url))
 
296
        except errors.UnstackableBranchFormat, e:
 
297
            return FailedSmartServerResponse(('UnstackableBranchFormat',
 
298
                str(e.format), e.url))
 
299
        except errors.NotStacked, e:
 
300
            return FailedSmartServerResponse(('NotStacked',))
 
301
        except UnicodeError, e:
 
302
            # If it is a DecodeError, than most likely we are starting
 
303
            # with a plain string
 
304
            str_or_unicode = e.object
 
305
            if isinstance(str_or_unicode, unicode):
 
306
                # XXX: UTF-8 might have \x01 (our seperator byte) in it.  We
 
307
                # should escape it somehow.
 
308
                val = 'u:' + str_or_unicode.encode('utf-8')
 
309
            else:
 
310
                val = 's:' + str_or_unicode.encode('base64')
 
311
            # This handles UnicodeEncodeError or UnicodeDecodeError
 
312
            return FailedSmartServerResponse((e.__class__.__name__,
 
313
                    e.encoding, val, str(e.start), str(e.end), e.reason))
 
314
        except errors.TransportNotPossible, e:
 
315
            if e.msg == "readonly transport":
 
316
                return FailedSmartServerResponse(('ReadOnlyError', ))
 
317
            else:
 
318
                raise
364
319
 
365
320
    def headers_received(self, headers):
366
321
        # Just a no-op at the moment.
367
 
        if 'hpss' in debug.debug_flags:
368
 
            self._trace('headers', repr(headers))
 
322
        pass
369
323
 
370
324
    def args_received(self, args):
371
325
        cmd = args[0]
373
327
        try:
374
328
            command = self._commands.get(cmd)
375
329
        except LookupError:
376
 
            if 'hpss' in debug.debug_flags:
377
 
                self._trace('hpss unknown request', 
378
 
                            cmd, repr(args)[1:-1])
379
330
            raise errors.UnknownSmartMethod(cmd)
380
 
        if 'hpss' in debug.debug_flags:
381
 
            from bzrlib.smart import vfs
382
 
            if issubclass(command, vfs.VfsRequest):
383
 
                action = 'hpss vfs req'
384
 
            else:
385
 
                action = 'hpss request'
386
 
            self._trace(action, 
387
 
                        '%s %s' % (cmd, repr(args)[1:-1]))
388
 
        self._command = command(
389
 
            self._backing_transport, self._root_client_path, self._jail_root)
 
331
        self._command = command(self._backing_transport)
390
332
        self._run_handler_code(self._command.execute, args, {})
391
333
 
 
334
    def prefixed_body_received(self, body_bytes):
 
335
        """No more body data will be received."""
 
336
        self._run_handler_code(self._command.do_body, (body_bytes,), {})
 
337
        # cannot read after this.
 
338
        self.finished_reading = True
 
339
 
 
340
    def body_chunk_received(self, chunk_bytes):
 
341
        self._run_handler_code(self._command.do_chunk, (chunk_bytes,), {})
 
342
 
392
343
    def end_received(self):
393
 
        if self._command is None:
394
 
            # no active command object, so ignore the event.
395
 
            return
396
344
        self._run_handler_code(self._command.do_end, (), {})
397
 
        if 'hpss' in debug.debug_flags:
398
 
            self._trace('end', '', include_time=True)
399
 
 
400
 
    def post_body_error_received(self, error_args):
401
 
        # Just a no-op at the moment.
402
 
        pass
403
 
 
404
 
 
405
 
def _translate_error(err):
406
 
    if isinstance(err, errors.NoSuchFile):
407
 
        return ('NoSuchFile', err.path)
408
 
    elif isinstance(err, errors.FileExists):
409
 
        return ('FileExists', err.path)
410
 
    elif isinstance(err, errors.DirectoryNotEmpty):
411
 
        return ('DirectoryNotEmpty', err.path)
412
 
    elif isinstance(err, errors.IncompatibleRepositories):
413
 
        return ('IncompatibleRepositories', str(err.source), str(err.target),
414
 
            str(err.details))
415
 
    elif isinstance(err, errors.ShortReadvError):
416
 
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
417
 
                str(err.actual))
418
 
    elif isinstance(err, errors.UnstackableRepositoryFormat):
419
 
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
420
 
    elif isinstance(err, errors.UnstackableBranchFormat):
421
 
        return ('UnstackableBranchFormat', str(err.format), err.url)
422
 
    elif isinstance(err, errors.NotStacked):
423
 
        return ('NotStacked',)
424
 
    elif isinstance(err, UnicodeError):
425
 
        # If it is a DecodeError, than most likely we are starting
426
 
        # with a plain string
427
 
        str_or_unicode = err.object
428
 
        if isinstance(str_or_unicode, unicode):
429
 
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
430
 
            # byte) in it, so this encoding could cause broken responses.
431
 
            # Newer clients use protocol v3, so will be fine.
432
 
            val = 'u:' + str_or_unicode.encode('utf-8')
433
 
        else:
434
 
            val = 's:' + str_or_unicode.encode('base64')
435
 
        # This handles UnicodeEncodeError or UnicodeDecodeError
436
 
        return (err.__class__.__name__, err.encoding, val, str(err.start),
437
 
                str(err.end), err.reason)
438
 
    elif isinstance(err, errors.TransportNotPossible):
439
 
        if err.msg == "readonly transport":
440
 
            return ('ReadOnlyError', )
441
 
    elif isinstance(err, errors.ReadError):
442
 
        # cannot read the file
443
 
        return ('ReadError', err.path)
444
 
    elif isinstance(err, errors.PermissionDenied):
445
 
        return ('PermissionDenied', err.path, err.extra)
446
 
    elif isinstance(err, errors.TokenMismatch):
447
 
        return ('TokenMismatch', err.given_token, err.lock_token)
448
 
    elif isinstance(err, errors.LockContention):
449
 
        return ('LockContention',)
450
 
    elif isinstance(err, MemoryError):
451
 
        # GZ 2011-02-24: Copy bzrlib.trace -Dmem_dump functionality here?
452
 
        return ('MemoryError',)
453
 
    # Unserialisable error.  Log it, and return a generic error
454
 
    trace.log_exception_quietly()
455
 
    return ('error', trace._qualified_exception_name(err.__class__, True),
456
 
        str(err))
457
345
 
458
346
 
459
347
class HelloRequest(SmartServerRequest):
495
383
request_handlers.register_lazy(
496
384
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
497
385
request_handlers.register_lazy(
498
 
    'Branch.get_config_file', 'bzrlib.smart.branch',
499
 
    'SmartServerBranchGetConfigFile')
500
 
request_handlers.register_lazy(
501
 
    'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
502
 
request_handlers.register_lazy(
503
 
    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
504
 
    'SmartServerBranchGetTagsBytes')
505
 
request_handlers.register_lazy(
506
 
    'Branch.set_tags_bytes', 'bzrlib.smart.branch',
507
 
    'SmartServerBranchSetTagsBytes')
508
 
request_handlers.register_lazy(
509
 
    'Branch.heads_to_fetch', 'bzrlib.smart.branch',
510
 
    'SmartServerBranchHeadsToFetch')
 
386
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
511
387
request_handlers.register_lazy(
512
388
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
513
389
request_handlers.register_lazy(
514
390
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
515
391
request_handlers.register_lazy(
516
392
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
517
 
request_handlers.register_lazy( 'Branch.revision_history',
518
 
    'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
519
 
request_handlers.register_lazy( 'Branch.set_config_option',
520
 
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOption')
521
 
request_handlers.register_lazy( 'Branch.set_config_option_dict',
522
 
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOptionDict')
523
 
request_handlers.register_lazy( 'Branch.set_last_revision',
524
 
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
393
request_handlers.register_lazy(
 
394
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
 
395
request_handlers.register_lazy(
 
396
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
525
397
request_handlers.register_lazy(
526
398
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
527
399
    'SmartServerBranchRequestSetLastRevisionInfo')
529
401
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
530
402
    'SmartServerBranchRequestSetLastRevisionEx')
531
403
request_handlers.register_lazy(
532
 
    'Branch.set_parent_location', 'bzrlib.smart.branch',
533
 
    'SmartServerBranchRequestSetParentLocation')
534
 
request_handlers.register_lazy(
535
404
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
536
405
request_handlers.register_lazy(
537
 
    'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
538
 
    'SmartServerBzrDirRequestCloningMetaDir')
539
 
request_handlers.register_lazy(
540
 
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
541
 
    'SmartServerRequestCreateBranch')
542
 
request_handlers.register_lazy(
543
 
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
544
 
    'SmartServerRequestCreateRepository')
545
 
request_handlers.register_lazy(
546
 
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
547
 
    'SmartServerRequestFindRepositoryV1')
548
 
request_handlers.register_lazy(
549
 
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
550
 
    'SmartServerRequestFindRepositoryV2')
551
 
request_handlers.register_lazy(
552
 
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
553
 
    'SmartServerRequestFindRepositoryV3')
554
 
request_handlers.register_lazy(
555
 
    'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
556
 
    'SmartServerBzrDirRequestConfigFile')
557
 
request_handlers.register_lazy(
558
 
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
559
 
    'SmartServerRequestInitializeBzrDir')
560
 
request_handlers.register_lazy(
561
 
    'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
562
 
    'SmartServerRequestBzrDirInitializeEx')
563
 
request_handlers.register_lazy(
564
 
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
565
 
request_handlers.register_lazy(
566
 
    'BzrDir.open_2.1', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir_2_1')
567
 
request_handlers.register_lazy(
568
 
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
569
 
    'SmartServerRequestOpenBranch')
570
 
request_handlers.register_lazy(
571
 
    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
572
 
    'SmartServerRequestOpenBranchV2')
573
 
request_handlers.register_lazy(
574
 
    'BzrDir.open_branchV3', 'bzrlib.smart.bzrdir',
575
 
    'SmartServerRequestOpenBranchV3')
 
406
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
 
407
request_handlers.register_lazy(
 
408
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
 
409
request_handlers.register_lazy(
 
410
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
 
411
request_handlers.register_lazy(
 
412
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
576
413
request_handlers.register_lazy(
577
414
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
578
415
request_handlers.register_lazy(
599
436
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
600
437
request_handlers.register_lazy(
601
438
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
602
 
request_handlers.register_lazy(
603
 
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
604
 
    'SmartServerPackRepositoryAutopack')
605
439
request_handlers.register_lazy('Repository.gather_stats',
606
440
                               'bzrlib.smart.repository',
607
441
                               'SmartServerRepositoryGatherStats')
613
447
request_handlers.register_lazy(
614
448
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
615
449
request_handlers.register_lazy(
616
 
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
617
 
request_handlers.register_lazy(
618
 
    'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
619
 
request_handlers.register_lazy(
620
 
    'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
621
 
request_handlers.register_lazy(
622
450
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
623
451
request_handlers.register_lazy(
624
452
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
625
453
request_handlers.register_lazy(
626
 
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
627
 
    'SmartServerRepositorySetMakeWorkingTrees')
628
 
request_handlers.register_lazy(
629
454
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
630
455
request_handlers.register_lazy(
631
 
    'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
632
 
    'SmartServerRepositoryGetRevIdForRevno')
633
 
request_handlers.register_lazy(
634
 
    'Repository.get_stream', 'bzrlib.smart.repository',
635
 
    'SmartServerRepositoryGetStream')
636
 
request_handlers.register_lazy(
637
 
    'Repository.get_stream_1.19', 'bzrlib.smart.repository',
638
 
    'SmartServerRepositoryGetStream_1_19')
639
 
request_handlers.register_lazy(
640
456
    'Repository.tarball', 'bzrlib.smart.repository',
641
457
    'SmartServerRepositoryTarball')
642
458
request_handlers.register_lazy(
645
461
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
646
462
request_handlers.register_lazy(
647
463
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
 
464
request_handlers.register_lazy(
 
465
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')