/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/request.py

  • Committer: John Arbash Meinel
  • Date: 2009-10-29 16:15:43 UTC
  • mto: This revision was merged to the branch mainline in revision 4780.
  • Revision ID: john@arbash-meinel.com-20091029161543-tdqlm2l4e2z5o7le
We don't have to pad 'short' records.

When writing a row, we reserve 120 bytes from the first node so that we
can write our 'B+Tree Graph Index' signature and other meta-information.
For the root node, we don't always use the 120 bytes, and for non-root
rows, we don't use that data at all. So we usually pad back that
record. However, for indexes that fit entirely in the root record,
we don't pad them to 4096, and it turns out we don't need to pad
them with the spare 120 bytes either.

I was doing a test with lots of 'chained' btree indexes, and this
extra padding ended up being 4.6M => 4.3M of wasted space. I imagine
that bzr-search will have a similar issue with tiny indexes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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).
 
27
"""
 
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 tempfile
 
35
import threading
 
36
 
 
37
from bzrlib import (
 
38
    bzrdir,
 
39
    errors,
 
40
    registry,
 
41
    revision,
 
42
    trace,
 
43
    urlutils,
 
44
    )
 
45
from bzrlib.lazy_import import lazy_import
 
46
lazy_import(globals(), """
 
47
from bzrlib.bundle import serializer
 
48
""")
 
49
 
 
50
 
 
51
jail_info = threading.local()
 
52
jail_info.transports = None
 
53
 
 
54
 
 
55
def _install_hook():
 
56
    bzrdir.BzrDir.hooks.install_named_hook(
 
57
        'pre_open', _pre_open_hook, 'checking server jail')
 
58
 
 
59
 
 
60
def _pre_open_hook(transport):
 
61
    allowed_transports = getattr(jail_info, 'transports', None)
 
62
    if allowed_transports is None:
 
63
        return
 
64
    abspath = transport.base
 
65
    for allowed_transport in allowed_transports:
 
66
        try:
 
67
            allowed_transport.relpath(abspath)
 
68
        except errors.PathNotChild:
 
69
            continue
 
70
        else:
 
71
            return
 
72
    raise errors.JailBreak(abspath)
 
73
 
 
74
 
 
75
_install_hook()
 
76
 
 
77
 
 
78
class SmartServerRequest(object):
 
79
    """Base class for request handlers.
 
80
 
 
81
    To define a new request, subclass this class and override the `do` method
 
82
    (and if appropriate, `do_body` as well).  Request implementors should take
 
83
    care to call `translate_client_path` and `transport_from_client_path` as
 
84
    appropriate when dealing with paths received from the client.
 
85
    """
 
86
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
 
87
    # *handler* is a different concept to the request.
 
88
 
 
89
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
 
90
        """Constructor.
 
91
 
 
92
        :param backing_transport: the base transport to be used when performing
 
93
            this request.
 
94
        :param root_client_path: the client path that maps to the root of
 
95
            backing_transport.  This is used to interpret relpaths received
 
96
            from the client.  Clients will not be able to refer to paths above
 
97
            this root.  If root_client_path is None, then no translation will
 
98
            be performed on client paths.  Default is '/'.
 
99
        :param jail_root: if specified, the root of the BzrDir.open jail to use
 
100
            instead of backing_transport.
 
101
        """
 
102
        self._backing_transport = backing_transport
 
103
        if jail_root is None:
 
104
            jail_root = backing_transport
 
105
        self._jail_root = jail_root
 
106
        if root_client_path is not None:
 
107
            if not root_client_path.startswith('/'):
 
108
                root_client_path = '/' + root_client_path
 
109
            if not root_client_path.endswith('/'):
 
110
                root_client_path += '/'
 
111
        self._root_client_path = root_client_path
 
112
        self._body_chunks = []
 
113
 
 
114
    def _check_enabled(self):
 
115
        """Raises DisabledMethod if this method is disabled."""
 
116
        pass
 
117
 
 
118
    def do(self, *args):
 
119
        """Mandatory extension point for SmartServerRequest subclasses.
 
120
 
 
121
        Subclasses must implement this.
 
122
 
 
123
        This should return a SmartServerResponse if this command expects to
 
124
        receive no body.
 
125
        """
 
126
        raise NotImplementedError(self.do)
 
127
 
 
128
    def execute(self, *args):
 
129
        """Public entry point to execute this request.
 
130
 
 
131
        It will return a SmartServerResponse if the command does not expect a
 
132
        body.
 
133
 
 
134
        :param *args: the arguments of the request.
 
135
        """
 
136
        self._check_enabled()
 
137
        return self.do(*args)
 
138
 
 
139
    def do_body(self, body_bytes):
 
140
        """Called if the client sends a body with the request.
 
141
 
 
142
        The do() method is still called, and must have returned None.
 
143
 
 
144
        Must return a SmartServerResponse.
 
145
        """
 
146
        if body_bytes != '':
 
147
            raise errors.SmartProtocolError('Request does not expect a body')
 
148
 
 
149
    def do_chunk(self, chunk_bytes):
 
150
        """Called with each body chunk if the request has a streamed body.
 
151
 
 
152
        The do() method is still called, and must have returned None.
 
153
        """
 
154
        self._body_chunks.append(chunk_bytes)
 
155
 
 
156
    def do_end(self):
 
157
        """Called when the end of the request has been received."""
 
158
        body_bytes = ''.join(self._body_chunks)
 
159
        self._body_chunks = None
 
160
        return self.do_body(body_bytes)
 
161
 
 
162
    def setup_jail(self):
 
163
        jail_info.transports = [self._jail_root]
 
164
 
 
165
    def teardown_jail(self):
 
166
        jail_info.transports = None
 
167
 
 
168
    def translate_client_path(self, client_path):
 
169
        """Translate a path received from a network client into a local
 
170
        relpath.
 
171
 
 
172
        All paths received from the client *must* be translated.
 
173
 
 
174
        :param client_path: the path from the client.
 
175
        :returns: a relpath that may be used with self._backing_transport
 
176
            (unlike the untranslated client_path, which must not be used with
 
177
            the backing transport).
 
178
        """
 
179
        if self._root_client_path is None:
 
180
            # no translation necessary!
 
181
            return client_path
 
182
        if not client_path.startswith('/'):
 
183
            client_path = '/' + client_path
 
184
        if client_path + '/' == self._root_client_path:
 
185
            return '.'
 
186
        if client_path.startswith(self._root_client_path):
 
187
            path = client_path[len(self._root_client_path):]
 
188
            relpath = urlutils.joinpath('/', path)
 
189
            if not relpath.startswith('/'):
 
190
                raise ValueError(relpath)
 
191
            return '.' + relpath
 
192
        else:
 
193
            raise errors.PathNotChild(client_path, self._root_client_path)
 
194
 
 
195
    def transport_from_client_path(self, client_path):
 
196
        """Get a backing transport corresponding to the location referred to by
 
197
        a network client.
 
198
 
 
199
        :seealso: translate_client_path
 
200
        :returns: a transport cloned from self._backing_transport
 
201
        """
 
202
        relpath = self.translate_client_path(client_path)
 
203
        return self._backing_transport.clone(relpath)
 
204
 
 
205
 
 
206
class SmartServerResponse(object):
 
207
    """A response to a client request.
 
208
 
 
209
    This base class should not be used. Instead use
 
210
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
 
211
    """
 
212
 
 
213
    def __init__(self, args, body=None, body_stream=None):
 
214
        """Constructor.
 
215
 
 
216
        :param args: tuple of response arguments.
 
217
        :param body: string of a response body.
 
218
        :param body_stream: iterable of bytestrings to be streamed to the
 
219
            client.
 
220
        """
 
221
        self.args = args
 
222
        if body is not None and body_stream is not None:
 
223
            raise errors.BzrError(
 
224
                "'body' and 'body_stream' are mutually exclusive.")
 
225
        self.body = body
 
226
        self.body_stream = body_stream
 
227
 
 
228
    def __eq__(self, other):
 
229
        if other is None:
 
230
            return False
 
231
        return (other.args == self.args and
 
232
                other.body == self.body and
 
233
                other.body_stream is self.body_stream)
 
234
 
 
235
    def __repr__(self):
 
236
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
 
237
            self.args, self.body)
 
238
 
 
239
 
 
240
class FailedSmartServerResponse(SmartServerResponse):
 
241
    """A SmartServerResponse for a request which failed."""
 
242
 
 
243
    def is_successful(self):
 
244
        """FailedSmartServerResponse are not successful."""
 
245
        return False
 
246
 
 
247
 
 
248
class SuccessfulSmartServerResponse(SmartServerResponse):
 
249
    """A SmartServerResponse for a successfully completed request."""
 
250
 
 
251
    def is_successful(self):
 
252
        """SuccessfulSmartServerResponse are successful."""
 
253
        return True
 
254
 
 
255
 
 
256
class SmartServerRequestHandler(object):
 
257
    """Protocol logic for smart server.
 
258
 
 
259
    This doesn't handle serialization at all, it just processes requests and
 
260
    creates responses.
 
261
    """
 
262
 
 
263
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
 
264
    # not contain encoding or decoding logic to allow the wire protocol to vary
 
265
    # from the object protocol: we will want to tweak the wire protocol separate
 
266
    # from the object model, and ideally we will be able to do that without
 
267
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
 
268
    # just a Protocol subclass.
 
269
 
 
270
    # TODO: Better way of representing the body for commands that take it,
 
271
    # and allow it to be streamed into the server.
 
272
 
 
273
    def __init__(self, backing_transport, commands, root_client_path,
 
274
        jail_root=None):
 
275
        """Constructor.
 
276
 
 
277
        :param backing_transport: a Transport to handle requests for.
 
278
        :param commands: a registry mapping command names to SmartServerRequest
 
279
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
 
280
        """
 
281
        self._backing_transport = backing_transport
 
282
        self._root_client_path = root_client_path
 
283
        self._commands = commands
 
284
        if jail_root is None:
 
285
            jail_root = backing_transport
 
286
        self._jail_root = jail_root
 
287
        self.response = None
 
288
        self.finished_reading = False
 
289
        self._command = None
 
290
 
 
291
    def accept_body(self, bytes):
 
292
        """Accept body data."""
 
293
        if self._command is None:
 
294
            # no active command object, so ignore the event.
 
295
            return
 
296
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
 
297
 
 
298
    def end_of_body(self):
 
299
        """No more body data will be received."""
 
300
        self._run_handler_code(self._command.do_end, (), {})
 
301
        # cannot read after this.
 
302
        self.finished_reading = True
 
303
 
 
304
    def _run_handler_code(self, callable, args, kwargs):
 
305
        """Run some handler specific code 'callable'.
 
306
 
 
307
        If a result is returned, it is considered to be the commands response,
 
308
        and finished_reading is set true, and its assigned to self.response.
 
309
 
 
310
        Any exceptions caught are translated and a response object created
 
311
        from them.
 
312
        """
 
313
        result = self._call_converting_errors(callable, args, kwargs)
 
314
 
 
315
        if result is not None:
 
316
            self.response = result
 
317
            self.finished_reading = True
 
318
 
 
319
    def _call_converting_errors(self, callable, args, kwargs):
 
320
        """Call callable converting errors to Response objects."""
 
321
        # XXX: most of this error conversion is VFS-related, and thus ought to
 
322
        # be in SmartServerVFSRequestHandler somewhere.
 
323
        try:
 
324
            self._command.setup_jail()
 
325
            try:
 
326
                return callable(*args, **kwargs)
 
327
            finally:
 
328
                self._command.teardown_jail()
 
329
        except (KeyboardInterrupt, SystemExit):
 
330
            raise
 
331
        except Exception, err:
 
332
            err_struct = _translate_error(err)
 
333
            return FailedSmartServerResponse(err_struct)
 
334
 
 
335
    def headers_received(self, headers):
 
336
        # Just a no-op at the moment.
 
337
        pass
 
338
 
 
339
    def args_received(self, args):
 
340
        cmd = args[0]
 
341
        args = args[1:]
 
342
        try:
 
343
            command = self._commands.get(cmd)
 
344
        except LookupError:
 
345
            raise errors.UnknownSmartMethod(cmd)
 
346
        self._command = command(
 
347
            self._backing_transport, self._root_client_path, self._jail_root)
 
348
        self._run_handler_code(self._command.execute, args, {})
 
349
 
 
350
    def end_received(self):
 
351
        if self._command is None:
 
352
            # no active command object, so ignore the event.
 
353
            return
 
354
        self._run_handler_code(self._command.do_end, (), {})
 
355
 
 
356
    def post_body_error_received(self, error_args):
 
357
        # Just a no-op at the moment.
 
358
        pass
 
359
 
 
360
 
 
361
def _translate_error(err):
 
362
    if isinstance(err, errors.NoSuchFile):
 
363
        return ('NoSuchFile', err.path)
 
364
    elif isinstance(err, errors.FileExists):
 
365
        return ('FileExists', err.path)
 
366
    elif isinstance(err, errors.DirectoryNotEmpty):
 
367
        return ('DirectoryNotEmpty', err.path)
 
368
    elif isinstance(err, errors.IncompatibleRepositories):
 
369
        return ('IncompatibleRepositories', str(err.source), str(err.target),
 
370
            str(err.details))
 
371
    elif isinstance(err, errors.ShortReadvError):
 
372
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
 
373
                str(err.actual))
 
374
    elif isinstance(err, errors.UnstackableRepositoryFormat):
 
375
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
 
376
    elif isinstance(err, errors.UnstackableBranchFormat):
 
377
        return ('UnstackableBranchFormat', str(err.format), err.url)
 
378
    elif isinstance(err, errors.NotStacked):
 
379
        return ('NotStacked',)
 
380
    elif isinstance(err, UnicodeError):
 
381
        # If it is a DecodeError, than most likely we are starting
 
382
        # with a plain string
 
383
        str_or_unicode = err.object
 
384
        if isinstance(str_or_unicode, unicode):
 
385
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
 
386
            # byte) in it, so this encoding could cause broken responses.
 
387
            # Newer clients use protocol v3, so will be fine.
 
388
            val = 'u:' + str_or_unicode.encode('utf-8')
 
389
        else:
 
390
            val = 's:' + str_or_unicode.encode('base64')
 
391
        # This handles UnicodeEncodeError or UnicodeDecodeError
 
392
        return (err.__class__.__name__, err.encoding, val, str(err.start),
 
393
                str(err.end), err.reason)
 
394
    elif isinstance(err, errors.TransportNotPossible):
 
395
        if err.msg == "readonly transport":
 
396
            return ('ReadOnlyError', )
 
397
    elif isinstance(err, errors.ReadError):
 
398
        # cannot read the file
 
399
        return ('ReadError', err.path)
 
400
    elif isinstance(err, errors.PermissionDenied):
 
401
        return ('PermissionDenied', err.path, err.extra)
 
402
    elif isinstance(err, errors.TokenMismatch):
 
403
        return ('TokenMismatch', err.given_token, err.lock_token)
 
404
    elif isinstance(err, errors.LockContention):
 
405
        return ('LockContention',)
 
406
    # Unserialisable error.  Log it, and return a generic error
 
407
    trace.log_exception_quietly()
 
408
    return ('error', str(err))
 
409
 
 
410
 
 
411
class HelloRequest(SmartServerRequest):
 
412
    """Answer a version request with the highest protocol version this server
 
413
    supports.
 
414
    """
 
415
 
 
416
    def do(self):
 
417
        return SuccessfulSmartServerResponse(('ok', '2'))
 
418
 
 
419
 
 
420
class GetBundleRequest(SmartServerRequest):
 
421
    """Get a bundle of from the null revision to the specified revision."""
 
422
 
 
423
    def do(self, path, revision_id):
 
424
        # open transport relative to our base
 
425
        t = self.transport_from_client_path(path)
 
426
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
 
427
        repo = control.open_repository()
 
428
        tmpf = tempfile.TemporaryFile()
 
429
        base_revision = revision.NULL_REVISION
 
430
        serializer.write_bundle(repo, revision_id, base_revision, tmpf)
 
431
        tmpf.seek(0)
 
432
        return SuccessfulSmartServerResponse((), tmpf.read())
 
433
 
 
434
 
 
435
class SmartServerIsReadonly(SmartServerRequest):
 
436
    # XXX: this request method belongs somewhere else.
 
437
 
 
438
    def do(self):
 
439
        if self._backing_transport.is_readonly():
 
440
            answer = 'yes'
 
441
        else:
 
442
            answer = 'no'
 
443
        return SuccessfulSmartServerResponse((answer,))
 
444
 
 
445
 
 
446
request_handlers = registry.Registry()
 
447
request_handlers.register_lazy(
 
448
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
 
449
request_handlers.register_lazy(
 
450
    'Branch.get_config_file', 'bzrlib.smart.branch',
 
451
    'SmartServerBranchGetConfigFile')
 
452
request_handlers.register_lazy(
 
453
    'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
 
454
request_handlers.register_lazy(
 
455
    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
 
456
    'SmartServerBranchGetTagsBytes')
 
457
request_handlers.register_lazy(
 
458
    'Branch.set_tags_bytes', 'bzrlib.smart.branch',
 
459
    'SmartServerBranchSetTagsBytes')
 
460
request_handlers.register_lazy(
 
461
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
 
462
request_handlers.register_lazy(
 
463
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
 
464
request_handlers.register_lazy(
 
465
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
 
466
request_handlers.register_lazy( 'Branch.revision_history',
 
467
    'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
 
468
request_handlers.register_lazy( 'Branch.set_config_option',
 
469
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOption')
 
470
request_handlers.register_lazy( 'Branch.set_last_revision',
 
471
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
472
request_handlers.register_lazy(
 
473
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
 
474
    'SmartServerBranchRequestSetLastRevisionInfo')
 
475
request_handlers.register_lazy(
 
476
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
 
477
    'SmartServerBranchRequestSetLastRevisionEx')
 
478
request_handlers.register_lazy(
 
479
    'Branch.set_parent_location', 'bzrlib.smart.branch',
 
480
    'SmartServerBranchRequestSetParentLocation')
 
481
request_handlers.register_lazy(
 
482
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
 
483
request_handlers.register_lazy(
 
484
    'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
 
485
    'SmartServerBzrDirRequestCloningMetaDir')
 
486
request_handlers.register_lazy(
 
487
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
 
488
    'SmartServerRequestCreateBranch')
 
489
request_handlers.register_lazy(
 
490
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
 
491
    'SmartServerRequestCreateRepository')
 
492
request_handlers.register_lazy(
 
493
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
 
494
    'SmartServerRequestFindRepositoryV1')
 
495
request_handlers.register_lazy(
 
496
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
 
497
    'SmartServerRequestFindRepositoryV2')
 
498
request_handlers.register_lazy(
 
499
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
 
500
    'SmartServerRequestFindRepositoryV3')
 
501
request_handlers.register_lazy(
 
502
    'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
 
503
    'SmartServerBzrDirRequestConfigFile')
 
504
request_handlers.register_lazy(
 
505
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
 
506
    'SmartServerRequestInitializeBzrDir')
 
507
request_handlers.register_lazy(
 
508
    'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
 
509
    'SmartServerRequestBzrDirInitializeEx')
 
510
request_handlers.register_lazy(
 
511
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
 
512
request_handlers.register_lazy(
 
513
    'BzrDir.open_2.1', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir_2_1')
 
514
request_handlers.register_lazy(
 
515
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
 
516
    'SmartServerRequestOpenBranch')
 
517
request_handlers.register_lazy(
 
518
    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
 
519
    'SmartServerRequestOpenBranchV2')
 
520
request_handlers.register_lazy(
 
521
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
 
522
request_handlers.register_lazy(
 
523
    'get', 'bzrlib.smart.vfs', 'GetRequest')
 
524
request_handlers.register_lazy(
 
525
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
 
526
request_handlers.register_lazy(
 
527
    'has', 'bzrlib.smart.vfs', 'HasRequest')
 
528
request_handlers.register_lazy(
 
529
    'hello', 'bzrlib.smart.request', 'HelloRequest')
 
530
request_handlers.register_lazy(
 
531
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
 
532
request_handlers.register_lazy(
 
533
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
 
534
request_handlers.register_lazy(
 
535
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
 
536
request_handlers.register_lazy(
 
537
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
 
538
request_handlers.register_lazy(
 
539
    'put', 'bzrlib.smart.vfs', 'PutRequest')
 
540
request_handlers.register_lazy(
 
541
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
 
542
request_handlers.register_lazy(
 
543
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
 
544
request_handlers.register_lazy(
 
545
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
 
546
request_handlers.register_lazy(
 
547
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
 
548
    'SmartServerPackRepositoryAutopack')
 
549
request_handlers.register_lazy('Repository.gather_stats',
 
550
                               'bzrlib.smart.repository',
 
551
                               'SmartServerRepositoryGatherStats')
 
552
request_handlers.register_lazy('Repository.get_parent_map',
 
553
                               'bzrlib.smart.repository',
 
554
                               'SmartServerRepositoryGetParentMap')
 
555
request_handlers.register_lazy(
 
556
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
 
557
request_handlers.register_lazy(
 
558
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
 
559
request_handlers.register_lazy(
 
560
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
 
561
request_handlers.register_lazy(
 
562
    'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
 
563
request_handlers.register_lazy(
 
564
    'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
 
565
request_handlers.register_lazy(
 
566
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
 
567
request_handlers.register_lazy(
 
568
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
 
569
request_handlers.register_lazy(
 
570
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
571
    'SmartServerRepositorySetMakeWorkingTrees')
 
572
request_handlers.register_lazy(
 
573
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
 
574
request_handlers.register_lazy(
 
575
    'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
 
576
    'SmartServerRepositoryGetRevIdForRevno')
 
577
request_handlers.register_lazy(
 
578
    'Repository.get_stream', 'bzrlib.smart.repository',
 
579
    'SmartServerRepositoryGetStream')
 
580
request_handlers.register_lazy(
 
581
    'Repository.get_stream_1.19', 'bzrlib.smart.repository',
 
582
    'SmartServerRepositoryGetStream_1_19')
 
583
request_handlers.register_lazy(
 
584
    'Repository.tarball', 'bzrlib.smart.repository',
 
585
    'SmartServerRepositoryTarball')
 
586
request_handlers.register_lazy(
 
587
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
 
588
request_handlers.register_lazy(
 
589
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
 
590
request_handlers.register_lazy(
 
591
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')