HPSS: Client-side objects

Andrew Bennetts andrew at canonical.com
Wed Apr 18 06:05:25 BST 2007


Aaron Bentley wrote:
> Andrew Bennetts wrote:
> > +    def open_repository(self):
> > +        path = self._path_for_remote_call(self._client)
> > +        response = self._client.call('BzrDir.find_repository', path)
> > +        assert response[0] in ('ok', 'norepository'), \
> > +            'unexpected response code %s' % (response,)
> > +        if response[0] == 'norepository':
> > +            raise errors.NoRepositoryPresent(self)
> > +        assert len(response) == 4, 'incorrect response length %s' % (response,)
> > +        if response[1] == '':
> > +            format = RemoteRepositoryFormat()
> > +            format.rich_root_data = response[2] == 'True'
> 
> ^^^ It seems the HPSS is returning 'ok', 'yes', 'no', 'True' (and
> presumably 'False') for boolean values.  I think perhaps you should
> standardize.

Changed to use 'yes'/'no' rather than 'True'/'False'.

> Also, the x = y == z is not especially clear.  I think we recommend
> surrounding the boolean expression with parentheses, e.g. x = (y == z)

Done.

> > +    def can_convert_format(self):
> > +        """Upgrading of remote bzrdirs is not supported yet."""
> > +        return False
> 
> Should we consider supporting the VFS upgrade approach?

It's not really safe to — the client could then upgrade the branch to a format
the server cannot read.  In general some thought needs to be given to how
upgrades should work.  A smart server could legitimately choose to store data in
a different format to the standard formats, I think (e.g. in a database),
although obviously this won't work while most things still fall back to VFS
methods.  So "upgrade" then becomes something that means "please upgrade this
branch to support these features: rich roots, subtrees", rather than "change the
files on disk like so".

So I think it's ok to refuse remote upgrades for now.  It's not a very common
desire anyway, because it's so slow at the moment.

> > +class RemoteBranch(branch.Branch):
> 
> ^^^^ Hmm.  Didn't we already have a class named this?  Oh yeah, back
> around revno 1390 :-)

:)

> > +    @needs_write_lock
> > +    def set_revision_history(self, rev_history):
> > +        # Send just the tip revision of the history; the server will generate
> > +        # the full history from that.  If the revision doesn't exist in this
> > +        # branch, NoSuchRevision will be raised.
> 
> This is not good enough, because we don't have a guarantee that the
> caller will provide the lefthand history.  See the assertions in
> Branch6.set_revision_history.

(I assume you mean BzrBranch6._write_revision_history, because it doesn't
override set_revision_history directly...)

I've spoken with Robert about this.  If BzrBranch6 can support
set_last_revision_info, then this should work.  The only difference in behaviour
with a BzrBranch6-via-RemoteBranch vs. a direct BzrBranch6 will be that passing
a non-lefthand history will silently become a lefthand history to the tip,
rather than an error.  I think this is ok.

> > +        path = self.bzrdir._path_for_remote_call(self._client)
> > +        if rev_history == []:
> > +            rev_id = ''
> 
> ^^^ I think NULL_REVISION/'null:' is much better than '' for this purpose.

NULL_REVISION is never stored to disk.  It's not part of the external ABI for
dealing bzr data.  So similarly, I don't think it's appropriate to send it
across the wire.  I considered using "null:" explicitly, but the apparent
consistency seems likely to lead to confusion.  "" is a perfectly reasonable way
to serialise the null revision in this context, I think.

What don't you like about ''?

> > === modified file 'bzrlib/branch.py'
> > --- bzrlib/branch.py	2007-04-13 07:18:57 +0000
> > +++ bzrlib/branch.py	2007-04-16 05:57:08 +0000
> > @@ -579,7 +579,8 @@
> >  
> >      def get_push_location(self):
> >          """Return the None or the location to push this branch to."""
> > -        raise NotImplementedError(self.get_push_location)bzrlib/branch.py
> > +        push_loc = self.get_config().get_user_option('push_location')
> > +        return push_loc
> 
> ^^^ I thought we were leaving details like this to particular
> implementations.

Nothing overrides it so far, so I call WHUI (We Haven't Used It).  I just moved
it up from BzrBranch to Branch, so that RemoteBranch can re-use it.

Particular implementations can always override get_config if they really want.

> >      def _get_checkout_format(self):
> >          """Return the most suitable metadir for a checkout of this branch.
> > -        Weaves are used if this branch's repostory uses weaves.
> > +        Weaves are used if this branch's repository uses weaves.
> >          """
> > +        from bzrlib.remote import RemoteBzrDir
> >          if isinstance(self.bzrdir, bzrdir.BzrDirPreSplitOut):
> >              from bzrlib.repofmt import weaverepo
> >              format = bzrdir.BzrDirMetaFormat1()
> >              format.repository_format = weaverepo.RepositoryFormat7()
> > +        elif isinstance(self.bzrdir, RemoteBzrDir):
> > +            format = bzrdir.BzrDirMetaFormat1()
> 
> ^^^ For a RemoteBzrDir, we should be using the same formats as the
> remote branch uses.  Can't we at least fall back to the VFS stuff?

I've changed this back, and overridden _get_checkout_format in RemoteBranch
instead.  It's a bit iffy to override an underscored method (it's not clear if
it's meant to be private to Branch, or to Branch+subclasses), but it at means we
can delegate to the VFS branch.

> > +# We can't use register_control_format because it adds it at a lower priority
> > +# than the existing branches, whereas this should take priority.
> 
> Can't we just register it first, then?

This just changed, actually, after discussion on IRC last night.  There's now a
register_control_server_format that is used for this registration:

    @classmethod
    def register_control_server_format(klass, format):
        """Register a control format for client-server environments.

        These formats will be tried before ones registered with
        register_control_format.  This gives implementations that decide to the
        chance to grab it before anything looks at the contents of the format
        file.
        """
        klass._control_formats.insert(0, format)

-Andrew.




More information about the bazaar mailing list