[PATCH 04 of 11] httppeer: use compression engine API for decompressing responses

Gregory Szorc gregory.szorc at gmail.com
Mon Nov 21 17:27:54 EST 2016


On Mon, Nov 21, 2016 at 2:18 PM, Augie Fackler <raf at durin42.com> wrote:

> On Sun, Nov 20, 2016 at 02:23:41PM -0800, Gregory Szorc wrote:
> > # HG changeset patch
> > # User Gregory Szorc <gregory.szorc at gmail.com>
> > # Date 1479678953 28800
> > #      Sun Nov 20 13:55:53 2016 -0800
> > # Node ID da1caf5b703a641f0167ece15fdff167a1343ec1
> > # Parent  0bef0b8fb9f44ed8568df6cfeabf162aa12b211e
> > httppeer: use compression engine API for decompressing responses
> >
> > In preparation for supporting multiple compression formats on the
> > wire protocol, we need all users of the wire protocol to use
> > compression engine APIs.
> >
> > This commit ports the HTTP wire protocol client to use the
> > compression engine API.
> >
> > The code for handling the HTTPException is a bit hacky. Essentially,
> > HTTPException could be thrown by any read() from the socket. However,
> > as part of porting the API, we no longer have a generator wrapping
> > the socket and we don't have a single place where we can trap the
> > exception. We solve this by introducing a proxy class that intercepts
> > read() and converts the exception appropriately.
> >
> > In the future, we could introduce a new compression engine API that
> > supports emitting a generator of decompressed chunks. This would
> > eliminate the need for the proxy class. As I said when I introduced
> > the decompressorreader() API, I'm not fond of it and would support
> > transitioning to something better. This can be done as a follow-up,
> > preferably once all the code is using the compression engine API and
> > we have a better idea of the API needs of all the consumers.
> >
> > diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
> > --- a/mercurial/httppeer.py
> > +++ b/mercurial/httppeer.py
> > @@ -12,7 +12,6 @@ import errno
> >  import os
> >  import socket
> >  import tempfile
> > -import zlib
> >
> >  from .i18n import _
> >  from .node import nullid
> > @@ -30,16 +29,26 @@ httplib = util.httplib
> >  urlerr = util.urlerr
> >  urlreq = util.urlreq
> >
> > -def zgenerator(f):
> > -    zd = zlib.decompressobj()
> > +# FUTURE: consider refactoring this API to use generators. This will
> > +# require a compression engine API to emit generators.
> > +def decompressresponse(response, engine):
> >      try:
> > -        for chunk in util.filechunkiter(f):
> > -            while chunk:
> > -                yield zd.decompress(chunk, 2**18)
> > -                chunk = zd.unconsumed_tail
> > +        reader = engine.decompressorreader(response)
> >      except httplib.HTTPException:
> >          raise IOError(None, _('connection ended unexpectedly'))
> > -    yield zd.flush()
> > +
> > +    # We need to wrap reader.read() so HTTPException on subsequent
> > +    # reads is also converted.
> > +    origread = reader.read
> > +    class readerproxy(reader.__class__):
> > +        def read(self, *args, **kwargs):
> > +            try:
> > +                return origread(*args, **kwargs)
>
> nit: I think you could use super(readerproxy, self).read() here (but
> do this as a follow-up if you agree with the idea)
>

Fun fact: I did this initially and ran into a wonky failure about super
expecting a type not a classobj or some other esoteric error I had never
seen before. I think this was due to the built-in file object type not
behaving like a real class/type. I could reproduce and add an inline
comment on why super isn't used if you want.


>
> > +            except httplib.HTTPException:
> > +                raise IOError(None, _('connection ended unexpectedly'))
> > +
> > +    reader.__class__ = readerproxy
> > +    return reader
> >
> >  class httppeer(wireproto.wirepeer):
> >      def __init__(self, ui, path):
> > @@ -202,7 +211,7 @@ class httppeer(wireproto.wirepeer):
> >                                        (safeurl, version))
> >
> >          if _compressible:
> > -            return util.chunkbuffer(zgenerator(resp))
> > +            return decompressresponse(resp, util.compengines['zlib'])
> >
> >          return resp
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20161121/9b2f9da0/attachment.html>


More information about the Mercurial-devel mailing list