Skip to content
Snippets Groups Projects
  1. Apr 02, 2018
  2. Apr 03, 2018
  3. Mar 28, 2018
  4. Mar 23, 2018
  5. Mar 28, 2018
    • Gregory Szorc's avatar
      wireproto: separate commands tables for version 1 and 2 commands · 45b39c69
      Gregory Szorc authored
      We can't easily reuse existing command handlers for version 2
      commands because the response types will be different. e.g. many
      commands return nodes encoded as hex. Our new wire protocol is
      binary safe, so we'll wish to encode nodes as binary.
      
      We /could/ teach each command handler to look at the protocol
      handler and change behavior based on the version in use. However,
      this would make logic a bit unwieldy over time and would make
      it harder to design a unified protocol handler interface. I think
      it's better to create a clean break between version 1 and version 2
      of commands on the server.
      
      What I imagine happening is we will have separate @wireprotocommand
      functions for each protocol generation. Those functions will parse the
      request, dispatch to a common function to process it, then generate
      the response in its own, transport-specific manner.
      
      This commit establishes a separate table for tracking version 1
      commands from version 2 commands. The HTTP server pieces have been
      updated to use this new table.
      
      Most commands are marked as both version 1 and version 2, so there is
      little practical impact to this change.
      
      A side-effect of this change is we now rely on transport registration
      in wireprototypes.TRANSPORTS and certain properties of the protocol
      interface. So a test had to be updated to conform.
      
      Differential Revision: https://phab.mercurial-scm.org/D2982
      45b39c69
    • Gregory Szorc's avatar
      wireproto: mark SSHv2 as a version 1 transport · 27527d8c
      Gregory Szorc authored
      The version component is used for filtering/routing wire protocol
      commands to their proper handler. The actual version 2 of the wire
      protocol commands will use a different encoding of responses. We
      already have tests using the version 2 SSH transport and version 2
      of the wire protocol commands won't be implemented atomically.
      
      This commit marks the SSHv2 transport as version 1 so it will
      still invoke the version 1 commands. Once the commands are all
      implemented in version 2, we can restore its proper behavior.
      
      Some tests had to be disabled as a result of this change.
      
      Differential Revision: https://phab.mercurial-scm.org/D2981
      27527d8c
    • Gregory Szorc's avatar
      wireproto: stop aliasing wire protocol types (API) · d5d665f6
      Gregory Szorc authored
      We generally shy away from aliasing module symbols. I think I
      was keeping this around for API compatibility. We've already made
      tons of other API breaks in the wire protocol code this release.
      What's one more?
      
      .. api::
      
         ``wireproto`` module no longer re-exports various types used to
         define responses to wire protocol commands. Access these types
         from the ``wireprototypes`` module.
      
      Differential Revision: https://phab.mercurial-scm.org/D2979
      d5d665f6
  6. Mar 26, 2018
    • Gregory Szorc's avatar
      wireproto: use CBOR for command requests · 3d0e2cd8
      Gregory Szorc authored
      Now that we're using CBOR in the new wire protocol, let's convert
      command requests to it.
      
      Before I wrote this patch and was even thinking about CBOR, I was
      thinking about how commands should be issued and came to the
      conclusion that we didn't need separate frames to represent the
      command name from its arguments. I already had a partially
      completed patch prepared to merge the frames.
      
      But with CBOR, it makes the implementation a bit simpler because
      we don't need to roll our own serialization.
      
      The changes here are a bit invasive. I tried to split this into
      multiple commits to make it easier to review. But it was just too
      hard.
      
      * "command name" and "command argument" frames have been collapsed
        into a "command request" frame.
      * The flags for this new frame are totally different.
      * Frame processing has been overhauled to reflect the new order
        of things.
      * Test fallout was significant. A handful of tests were removed.
      
      Altogether, I think the new code is simpler. We don't have
      complicated state around receiving commands. We're either receiving
      command request frames or command data frames. We /could/
      potentially collapse command data frames into command request
      frames. Although I'd have to think a bit more about this before
      I do it.
      
      Differential Revision: https://phab.mercurial-scm.org/D2951
      3d0e2cd8
    • Gregory Szorc's avatar
      wireproto: define frame to represent progress updates · b0041036
      Gregory Szorc authored
      Today, a long-running operation on a server may run without any sign
      of progress on the client. This can lead to the conclusion that the
      server has hung or the connection has dropped. In fact, connections
      can and do time out due to inactivity. And a long-running server
      operation can result in the connection dropping prematurely because
      no data is being sent!
      
      While we're inventing the new wire protocol, let's provide a mechanism
      for communicating progress on potentially expensive server-side events.
      
      We introduce a new frame type that conveys "progress" updates. This
      frame type essentially holds the data required to formulate a
      ``ui.progress()`` call.
      
      We only define the frame right now. Implementing it will be a bit of
      work since there is no analog to progress frames in the existing
      wire protocol. We'll need to teach the ui object to write to the
      wire protocol, etc.
      
      The use of a CBOR map may seem wasteful, as this will encode key
      names in every frame. This *is* wasteful. However, maps are
      extensible. And the intent is to always use compression via
      streams. Compression will make the overhead negligible since repeated
      strings will be mostly eliminated over the wire.
      
      Differential Revision: https://phab.mercurial-scm.org/D2902
      b0041036
  7. Mar 28, 2018
    • Gregory Szorc's avatar
      wireproto: syntax for encoding CBOR into frames · cc5a040f
      Gregory Szorc authored
      We just vendored a library for encoding and decoding the CBOR
      data format. While the intent of that vendor was to support state
      files, CBOR is really a nice data format. It is extensible and
      compact.
      
      I've been feeling dirty inventing my own data formats for
      frame payloads. While custom formats can always beat out a generic
      format, there is a cost to be paid in terms of implementation,
      comprehension, etc. CBOR is compact enough that I'm not too
      worried about efficiency loss. I think the benefits of using
      a standardized format outweigh rolling our own formats. So
      I plan to make heavy use of CBOR in the wire protocol going
      forward.
      
      This commit introduces support for encoding CBOR data in frame
      payloads to our function to make a frame from a human string.
      We do need to employ some low-level Python code in order to
      evaluate a string as a Python expression. But other than that,
      this should hopefully be pretty straightforward.
      
      Unit tests for this function have been added.
      
      Differential Revision: https://phab.mercurial-scm.org/D2948
      cc5a040f
  8. Mar 26, 2018
    • Gregory Szorc's avatar
      wireproto: explicit API to create outgoing streams · 5fadc63a
      Gregory Szorc authored
      It is better to create outgoing streams through the reactor so the
      reactor knows about what streams are active and can track them
      accordingly.
      
      Test output changes slightly because frames from subsequent responses
      no longer have the "stream begin" stream flag set because the stream
      is now used across all responses.
      
      Differential Revision: https://phab.mercurial-scm.org/D2947
      5fadc63a
    • Gregory Szorc's avatar
      wireproto: add streams to frame-based protocol · 9bfcbe4f
      Gregory Szorc authored
      Previously, the frame-based protocol was just a series of frames,
      with each frame associated with a request ID.
      
      In order to scale the protocol, we'll want to enable the use of
      compression. While it is possible to enable compression at the
      socket/pipe level, this has its disadvantages. The big one is it
      undermines the point of frames being standalone, atomic units that
      can be read and written: if you add compression above the framing
      protocol, you are back to having a stream-based protocol as opposed
      to something frame-based.
      
      So in order to preserve frames, compression needs to occur at
      the frame payload level.
      
      Compressing each frame's payload individually will limit compression
      ratios because the window size of the compressor will be limited
      by the max frame size, which is 32-64kb as currently defined. It
      will also add CPU overhead, as it is more efficient for compressors
      to operate on fewer, larger blocks of data than more, smaller blocks.
      
      So compressing each frame independently is out.
      
      This means we need to compress each frame's payload as if it is part
      of a larger stream.
      
      The simplest approach is to have 1 stream per connection. This
      could certainly work. However, it has disadvantages (documented below).
      
      We could also have 1 stream per RPC/command invocation. (This is the
      model HTTP/2 goes with.) This also has disadvantages.
      
      The main disadvantage to one global stream is that it has the very
      real potential to create CPU bottlenecks doing compression. Networks
      are only getting faster and the performance of single CPU cores has
      been relatively flat. Newer compression formats like zstandard offer
      better CPU cycle efficiency than predecessors like zlib. But it still
      all too common to saturate your CPU with compression overhead long
      before you saturate the network pipe.
      
      The main disadvantage with streams per request is that you can't
      reap the benefits of the compression context for multiple requests.
      For example, if you send 1000 RPC requests (or HTTP/2 requests for
      that matter), the response to each would have its own compression
      context. The overall size of the raw responses would be larger because
      compression contexts wouldn't be able to reference data from another
      request or response.
      
      The approach for streams as implemented in this commit is to support
      N streams per connection and for streams to potentially span requests
      and responses. As explained by the added internals docs, this
      facilitates servers and clients delegating independent streams and
      compression to independent threads / CPU cores. This helps alleviate
      the CPU bottleneck of compression. This design also allows compression
      contexts to be reused across requests/responses. This can result in
      improved compression ratios and less overhead for compressors and
      decompressors having to build new contexts.
      
      Another feature that was defined was the ability for individual frames
      within a stream to declare whether that individual frame's payload
      uses the content encoding (read: compression) defined by the stream.
      The idea here is that some servers may serve data from a combination
      of caches and dynamic resolution. Data coming from caches may be
      pre-compressed. We want to facilitate servers being able to essentially
      stream bytes from caches to the wire with minimal overhead. Being
      able to mix and match with frames are compressed within a stream
      enables these types of advanced server functionality.
      
      This commit defines the new streams mechanism. Basic code for
      supporting streams in frames has been added. But that code is
      seriously lacking and doesn't fully conform to the defined protocol.
      For example, we don't close any streams. And support for content
      encoding within streams is not yet implemented. The change was
      rather invasive and I didn't think it would be reasonable to implement
      the entire feature in a single commit.
      
      For the record, I would have loved to reuse an existing multiplexing
      protocol to build the new wire protocol on top of. However, I couldn't
      find a protocol that offers the performance and scaling characteristics
      that I desired. Namely, it should support multiple compression
      contexts to facilitate scaling out to multiple CPU cores and
      compression contexts should be able to live longer than single RPC
      requests. HTTP/2 *almost* fits the bill. But the semantics of HTTP
      message exchange state that streams can only live for a single
      request-response. We /could/ tunnel on top of HTTP/2 streams and
      frames with HEADER and DATA frames. But there's no guarantee that
      HTTP/2 libraries and proxies would allow us to use HTTP/2 streams
      and frames without the HTTP message exchange semantics defined in
      RFC 7540 Section 8. Other RPC protocols like gRPC tunnel are built
      on top of HTTP/2 and thus preserve its semantics of stream per
      RPC invocation. Even QUIC does this. We could attempt to invent a
      higher-level stream that spans HTTP/2 streams. But this would be
      violating HTTP/2 because there is no guarantee that HTTP/2 streams
      are routed to the same server. The best we can do - which is what
      this protocol does - is shoehorn all request and response data into
      a single HTTP message and create streams within. At that point, we've
      defined a Content-Type in HTTP parlance. It just so happens our
      media type can also work as a standalone, stream-based protocol,
      without leaning on HTTP or similar protocol.
      
      Differential Revision: https://phab.mercurial-scm.org/D2907
      9bfcbe4f
    • Gregory Szorc's avatar
      wireproto: start to associate frame generation with a stream · 3ed34454
      Gregory Szorc authored
      An upcoming commit will introduce "streams" into the frame-based wire
      protocol. In preparation for this invasive change, we introduce a basic
      "stream" class and have all operations that create frames also operate
      alongside a stream instance.
      
      Differential Revision: https://phab.mercurial-scm.org/D2906
      3ed34454
    • Gregory Szorc's avatar
      tests: fix duplicate and failing test · 12bfc724
      Gregory Szorc authored
      There were two "testconflictingrequestid" methods. Naturally this isn't
      an error in Python. And by our luck, the test was failing.
      
      So we rename the test and fix it to pass.
      
      As part of this, _sendsingleframe() now takes a frame, not a string
      describing the frame. This is better because action at a distance can
      be confusing.
      
      Differential Revision: https://phab.mercurial-scm.org/D2950
      12bfc724
  9. Apr 02, 2018
    • Gregory Szorc's avatar
      debugcommands: drop offset and length from debugindex by default · d4e62df1
      Gregory Szorc authored
      These fields are an implementation detail of revlog storage. As
      such, they are not part of the generic storage "index" interface
      and shouldn't be displayed by default.
      
      Because we don't have another way to display these fields, we've
      retained support for printing these fields via --verbose.
      
      Yes, I know we should probably be doing all this formatting using
      modern formatting/templater APIs. I didn't feel like scope
      bloating this patch.
      
      Differential Revision: https://phab.mercurial-scm.org/D3028
      d4e62df1
    • Gregory Szorc's avatar
      debugcommands: drop base revision from debugindex · 009d0283
      Gregory Szorc authored
      Revlog index data consists of generic index metadata that will
      likely be implemented across all storage engines and revlog-specifc
      metadata.
      
      Most tests printing index data only care about the generic fields.
      
      This commit drops the printing of the base revision from
      `hg debugindex`. This value is an implementation detail of
      revlogs / delta chains. If tests are interested in verifying this
      implementation detail, `hg debugdeltachain` is a better command.
      
      Most tests were skipping over this field anyway. Tests that weren't
      looked like they were newer. So my guess is we forgot to make them
      skip the field to match the style of the older tests. This reinforces
      my belief that the base revision is not worth having in
      `hg debugindex`.
      
      Differential Revision: https://phab.mercurial-scm.org/D3027
      009d0283
    • Gregory Szorc's avatar
      tests: use debugdeltachain where appropriate · 806b07d7
      Gregory Szorc authored
      Some tests are verifying delta chain type things. This metadata
      has more to do with a revlog implementation details than index
      data, which is theoretically generic.
      
      This commit ports some tests to `hg debugdeltachain`, as it is the
      more appropriate debug command for looking at delta metadata.
      
      Differential Revision: https://phab.mercurial-scm.org/D3026
      806b07d7
    • Gregory Szorc's avatar
      tests: don't use revlog paths in tests · 43548139
      Gregory Szorc authored
      Debug commands operating on revlogs don't need the full revlog
      path: they can accept the relative path to a tracked file or use
      -c/-m to specify a changelog or manifest.
      
      Not using the revlog path makes tests more resilient to cases
      where revlogs aren't being used for storage.
      
      Differential Revision: https://phab.mercurial-scm.org/D3025
      43548139
  10. Mar 17, 2018
  11. Mar 23, 2018
  12. Mar 18, 2018
  13. Mar 17, 2018
    • Yuya Nishihara's avatar
      templater: drop unneeded generator from mappable object · b4630e33
      Yuya Nishihara authored
      Per the definition of the show() interface, it can return a bytes.
      b4630e33
    • Yuya Nishihara's avatar
      8c84dc82
    • Yuya Nishihara's avatar
      templatekw: do not directly call .gen · 45987e2b
      Yuya Nishihara authored
      45987e2b
    • Yuya Nishihara's avatar
      templater: define interface for objects requiring unwraphybrid() · 83e1bbd4
      Yuya Nishihara authored
      Prepares for introducing another hybrid-like data type. show() takes context
      as an argument so a wrapper class may render its items by pre-configured
      template:
      
        def show(self, context, mapping):
            return (context.expand(self._tmpl, mapping + lm) for lm in self._mappings)
      83e1bbd4
    • Yuya Nishihara's avatar
      templater: pass (context, mapping) down to unwraphybrid() · 7d3bc1d4
      Yuya Nishihara authored
      See the subsequent patches for why.
      
      I initially thought it would be wrong to pass a mapping to flatten() and
      stringify() since these functions may be applied to a tree of generators,
      where each node should be bound to the mapping when it was evaluated. But,
      actually that isn't a problem. If an intermediate node has to override a
      mapping dict, it can do on unwraphybrid() and yield "unwrapped" generator
      of byte strings:
      
         "{f(g(v))}"  # literal template example.
             ^^^^     # g() want to override a mapping, so it returns a wrapped
                      # object 'G{V}' with partial mapping 'lm' attached.
           ^^^^^^^    # f() stringifies 'G{V}', starting from a mapping 'm'.
                      # when unwrapping 'G{}', it updates 'm' with 'lm', and
                      # passes it to 'V'.
      
      This structure is important for the formatter (and the hgweb) to build a
      static template keyword, which can't access a mapping dict until evaluation
      phase.
      7d3bc1d4
  14. Apr 02, 2018
    • Martin von Zweigbergk's avatar
      scmutil: add method for looking up a context given a revision symbol · 0194dac7
      Martin von Zweigbergk authored
      changectx's constructor currently supports a mix if inputs:
      
        * integer revnums
        * binary nodeids
        * '.', 'tip', 'null'
        * stringified revnums
        * namespaced identifiers (e.g. bookmarks and tags)
        * hex nodeids
        * partial hex nodeids
      
      The first two are always internal [1]. The other five can be specified
      by the user. The third type ('.', 'tip', 'null') often comes from
      either the user or internal callers. We probably have some internal
      callers that pass hex nodeids too, perhaps even partial ones
      (histedit?). There are only a few callers that pass user-supplied
      strings: revsets.stringset, peer.lookup, webutil.changeidctx, and
      maybe one or two more.
      
      Supporting this mix of things in the constructor is convenient, but a
      bit strange, IMO. For example, if repo[node] is given a node that's
      not in the repo, it will first check if it's bookmark etc before
      raising an exception. Of course, the risk of it being a bookmark is
      extremely small, but it just feels ugly.
      
      Also, a problem with having this code in the constructor (whether it
      supports a mix of types or not) is that it's harder to override (I'd
      like to override it, and that's how this series started).
      
      This patch starts moving out the handling of user-supplied strings by
      introducing scmutil.revsymbol(). So far, that just checks that the
      input is indeed a string, and then delegates to repo[symbol]. The
      patch also calls it from revsets.stringset to prove that it works.
      
       [1] Well, you probably can enter a 20-byte binary nodeid on the
           command line, but I don't think we should care to preserve
           support for that.
      
      Differential Revision: https://phab.mercurial-scm.org/D3024
      0194dac7
Loading