Skip to content
Snippets Groups Projects
  1. Jan 22, 2018
    • Gregory Szorc's avatar
      exchange: send bundle2 stream clones uncompressed · a84dbc87
      Gregory Szorc authored
      Stream clones don't compress well. And compression undermines
      a point of stream clones which is to trade significant CPU
      reductions by increasing size.
      
      Building upon our introduction of metadata to communicate bundle
      information back to callers of exchange.getbundlechunks(), we add
      an attribute to the bundler that communicates whether the bundle is
      best left uncompressed. We return this attribute as part of the bundle
      metadata. And the wire protocol honors it when determining whether
      to compress the wire protocol response.
      
      The added test demonstrates that the raw result from the wire
      protocol is not compressed. It also demonstrates that the server
      will serve stream responses when the feature isn't enabled. We'll
      address that in another commit.
      
      The effect of this change is that server-side CPU usage for bundle2
      stream clones is significantly reduced by removing zstd compression.
      For the mozilla-unified repository:
      
      before: 37.69 user 8.01 system
      after:  27.38 user 7.34 system
      
      Assuming things are CPU bound, that ~10s reduction would translate to
      faster clones on the client. zstd can decompress at >1 GB/s. So the
      overhead from decompression on the client is small in the grand scheme
      of things. But if zlib compression were being used, the overhead would
      be much greater.
      
      Differential Revision: https://phab.mercurial-scm.org/D1926
      a84dbc87
    • Gregory Szorc's avatar
      tests: update test to work with Git 2.16 · 8144f1b0
      Gregory Szorc authored
      It looks like Git 2.16 removed the "..." from some strings.
      Glob over those characters in the test output.
      
      Differential Revision: https://phab.mercurial-scm.org/D1935
      8144f1b0
  2. Jan 20, 2018
    • Gregory Szorc's avatar
      exchange: return bundle info from getbundlechunks() (API) · ba15580e
      Gregory Szorc authored
      We generally want a mechanism to pass information about the
      generated bundle back to callers (in addition to the byte stream).
      Ideally we would return a bundler from this function and have the
      caller code to an interface. But the bundling APIs are not great
      and getbundlechunks() is the best API we have for obtaining bundle
      contents in a unified manner.
      
      We change getbundlechunks() to return a dict that we can use to
      communicate metadata.
      
      We populate that dict with the bundle version number to demonstrate
      some value.
      
      .. api::
      
         exchange.getbundlechunks() now returns a 2-tuple instead of just
         an iterator.
      
      Differential Revision: https://phab.mercurial-scm.org/D1925
      ba15580e
    • Gregory Szorc's avatar
      exchange: make stream bundle part deterministic · 08cc94dd
      Gregory Szorc authored
      repo.requirements is a set. We need to sort it so the part
      content is deterministic.
      
      Differential Revision: https://phab.mercurial-scm.org/D1924
      08cc94dd
    • Gregory Szorc's avatar
      bundle2: specify what capabilities will be used for · c97639ad
      Gregory Szorc authored
      We currently assume there is a symmetric relationship of bundle2
      capabilities between client and server. However, this may not always be
      the case.
      
      We need a bundle2 capability to advertise bundle2 streaming clone support
      on servers to differentiate it from the existing, legacy streaming clone
      support.
      
      However, servers may wish to disable streaming clone support. If bundle2
      capabilities were the same between client and server, a client (which
      may also be a server) that has disabled streaming clone support would
      not be able to perform a streaming clone itself!
      
      This commit introduces a "role" argument to bundle2.getrepocaps() that
      explicitly defines the role being performed. This will allow us (and
      extensions) to alter bundle2 capabilities depending on the operation
      being performed.
      
      Differential Revision: https://phab.mercurial-scm.org/D1923
      c97639ad
    • Gregory Szorc's avatar
      wireproto: don't compress errors from getbundle() · 9d249f3d
      Gregory Szorc authored
      Errors should be small. There's no real need to compress them.
      Truth be told, there's no good reason to not compress them either.
      But leaving them uncompressed makes it easier to test failures
      by looking at the raw HTTP response. This makes it easier for us
      to write tests. It may make it easier for people writing their
      own clients.
      
      Differential Revision: https://phab.mercurial-scm.org/D1922
      9d249f3d
  3. Jan 21, 2018
  4. Jan 20, 2018
  5. Jan 22, 2018
    • Gregory Szorc's avatar
      convert: use a collections.deque · eefabd9e
      Gregory Szorc authored
      This function was doing a list.pop(0) on a list whose length
      was the number of revisions to convert. Popping an early element
      from long lists is not an efficient operation.
      
      collections.deque supports efficient inserts and pops at both
      ends. So we switch to that data structure.
      
      When converting the mozilla-unified repository, which has 445,748
      revisions, this change makes the "sorting..." step of
      `hg convert --sourcesort` significantly faster:
      
      before: ~59.2s
      after:   ~1.3s
      
      Differential Revision: https://phab.mercurial-scm.org/D1934
      eefabd9e
  6. Jan 21, 2018
    • Martin von Zweigbergk's avatar
      repair: invalidate volatile sets after stripping · 128dd940
      Martin von Zweigbergk authored
      Matt Harbison reported that some tests were broken on Windows after
      1a09dad8b85a (evolution: report new unstable changesets,
      2018-01-14). The failures were exactly as seen in this patch. The
      failures actually seemed correct, which made me wonder why they didn't
      fail the same way on Linux. It turned out to be a cache invalidation
      problem.
      
      The new orphan mentioned in the test case actually does get created
      when we're re-applying the temporary bundle that's created while
      stripping. However, without the invalidation, it appears that there
      was already an orphan before applying the temporary bundle.
      
      The warnings about unknown working parent appear because the
      aformentioned changeset means that we're now accessing the dirstate
      while it's invalid.
      
      We may want to suppress these messages that happen in the intermediate
      strip state, but they're technically correct (although confusing to
      the user), so I think just fixing the cache invalidation is fine for
      now.
      
      I haven't figured out why the caches seemed to get correctly
      invalidated on Windows.
      
      Differential Revision: https://phab.mercurial-scm.org/D1933
      128dd940
    • Matt Harbison's avatar
      subrepo: handle 'C:' style paths on the command line (issue5770) · 0c0689a7
      Matt Harbison authored
      If you think 'C:' and 'C:\' are equivalent paths, see the inline comment before
      proceeding.
      
      The problem here was that several commands that take a URL argument (incoming,
      outgoing, pull, and push) will use that value to set 'repo._subtoppath' on the
      repository object after command specific manipulation of it, but before
      converting it to an absolute path.  When an operation is performed on a relative
      subrepo, subrepo._abssource() will posixpath.join() this value with the relative
      subrepo path.  That adds a '/' after the drive letter, changing how it is
      evaluated by abspath()/realpath() in vfsmod.vfs(..., realpath=True) as the
      subrepo is instantiated.
      
      I initially tried sanitizing the path in url.localpath(), because url.isabs()
      only checks that it starts with a drive letter.  By the sample behavior, this is
      clearly not an absolute path.  (Though the comment in isabs() is weasely- this
      style path can't be joined either.)  But not everything funnels through there,
      and it required explicitly calling localpath() in hg.parseurl() and assigning to
      url.path to fix.  But then tests failed with urls like 'a#0'.
      
      Next up was sanitizing the path in the url constructor.  That caused doctest
      failures, because there are drive letter tests, so those got expanded in system
      specific ways.  Yuya correctly pointed out that util.url is a parser, and
      shouldn't be substituting the path too.
      
      Rather than fixing every command call site, just convert it in the common
      subrepo location.  I don't see any sanitizing on the path config options, so I
      fixed those too.  Note that while the behavior is fixed here, there are still
      places where 'comparing with C:' gets printed out, and that's not great for
      debugging purposes.  (Specifically I saw it in `hg incoming -B C:`, without
      subrepos.)  While clone will write out an absolute default path, I wonder what
      would happen if a user edited that path to be 'C:'.  (I don't think supporting
      relative paths in .hgrc is a sane thing to do, but while we're poking holes in
      things...)
      
      Since this is such an oddball case, it still leaks through in places, and there
      seems to be a lot of duplicate url parsing, maybe the url parsing should be
      moved to dispatch, and provide the command with a url object?  Then we could
      convert this to an absolute path once, and not have to worry about it in the
      rest of the code.
      
      I also checked '--cwd C:' on the command line, and it was previously working
      because os.chdir() will DTRT.
      
      Finally, one other note from the url.localpath() experimenting.  I don't see any
      cases where 'self._hostport' can hold a drive letter.  So I'm wondering if that
      is wrong/old code.
      0c0689a7
  7. Jan 22, 2018
    • Matt Harbison's avatar
      dummysmtpd: don't die on client connection errors · 75bae697
      Matt Harbison authored
      The connection refused error in test-patchbomb-tls.t[1] is sporadic, but one of
      the more often seen errors on Windows.  I added enough logging to a file and
      dumped it out at the end to make the following observations:
      
        - The listening socket is successfully created and bound to the port, and the
          "listening at..." message is always logged.
      
        - Generally, the following is the entire log output, with the "accepted ..."
          message having been added after `sslutil.wrapserversocket`:
      
                listening at localhost:$HGPORT
                $LOCALIP ssl error
                accepted connect
                accepted connect
                $LOCALIP from=quux to=foo, bar
                $LOCALIP ssl error
      
        - In the cases that fail, asyncore.loop() in the run() method is exiting, but
          not with an exception.
      
        - In the cases that fail, the following is logged right after "listening ...":
      
              Traceback (most recent call last):
                File "c:\\Python27\\lib\\asyncore.py", line 83, in read
                  obj.handle_read_event()
                File "c:\\Python27\\lib\\asyncore.py", line 443, in handle_read_event
                  self.handle_accept()
                File "../tests/dummysmtpd.py", line 80, in handle_accept
                  conn = sslutil.wrapserversocket(conn, ui, certfile=self._certfile)
                File "..\\mercurial\\sslutil.py", line 570, in wrapserversocket
                  return sslcontext.wrap_socket(sock, server_side=True)
                File "c:\\Python27\\lib\\ssl.py", line 363, in wrap_socket
                  _context=self)
                File "c:\\Python27\\lib\\ssl.py", line 611, in __init__
                  self.do_handshake()
                File "c:\\Python27\\lib\\ssl.py", line 840, in do_handshake
                  self._sslobj.do_handshake()
              error: [Errno 10054] $ECONNRESET$
      
        - If the base class handler is overridden completely, the the first "ssl
          error" line is replaced by the stacktrace, but the other lines are
          unchanged.  The client behaves no differently, whether or not the server
          stacktraced.
      
      In general, `./run-tests.py --local -j9 -t9000 test-patchbomb-tls.t
      --runs-per-test 20` would show the issue after a run or two.  With this change,
      `./run-tests.py --local -j9 -t9000 test-patchbomb-tls.t --loop` ran 800 times
      without a hiccup.  This makes me wonder if the other connection refused messages
      that bubble up on occasion are caused by a similar issue.  It seems a bit
      drastic to kill the whole server on account of a single communication failure
      with a client.
      
      # no-check-commit because of handle_error()
      
      [1] https://buildbot.mercurial-scm.org/builders/Win7%20x86_64%20hg%20tests/builds/421/steps/run-tests.py%20%28python%202.7.13%29/logs/stdio
      75bae697
  8. Jan 21, 2018
  9. Jan 20, 2018
  10. Jan 17, 2018
    • Boris Feld's avatar
      streamclone: also stream caches to the client · 5f5fb279
      Boris Feld authored
      When stream clone is used over bundle2, relevant cache files are also streamed.
      This is expected to be a massive performance win for clone since no important
      cache will have to be recomputed.
      
      Some performance numbers:
      
      (All times are wall-clock times in seconds, 2 attempts per case.)
      
      # Mozilla-Central
      
      ## Clone over ssh over lan
      V1 streaming: 234.3 239.6
      V2 streaming: 248.4 243.7
      
      ## Clone over ssh over Internet
      V1 streaming: 175.5 110.9
      V2 streaming: 109.1 111.0
      
      ## Clone over HTTP over lan
      V1 streaming: 105.3 105.6
      V2 streaming: 112.7 111.4
      
      ## Clone over HTTP over internet
      V1 streaming: 105.6 114.6
      V2 streaming: 226.7 225.9
      
      ## Hg tags
      V1 streaming (no cache): 1.084 1.071
      V2 streaming (cache):    0.312 0.325
      
      ## Hg branches
      V1 streaming (no cache):   14.047 14.148
      V2 streaming (with cache):  0.312  0.333
      
      # Pypy
      
      ## Clone over ssh over internet
      V1 streaming: 29.4 30.1
      V2 streaming: 31.2 30.1
      
      ## Clone over http over internet
      V1 streaming: 29.7 29.7
      V2 streaming: 75.2 72.9
      
      (since ssh and lan are not affected, there seems to be an issue with how we
      read/write the http stream on connection with latency, unrelated to the format)
      
      ## Hg tags
      V1 streaming (no cache):   1.752 1.664
      V2 streaming (with cache): 0.274 0.260
      
      ## Hg branches
      V1 streaming (no cache):   4.469 4.728
      V2 streaming (with cache): 0.318 0.321
      
      # Private repository:
          * 500K revision revisions
          * 11K topological heads
          * 28K branch heads
      
      ## hg tags
      no cache:   1543.332
      with cache:    4.900
      
      ## hg branches
      no cache:   91.828
      with cache:  2.955
      5f5fb279
    • Boris Feld's avatar
      caches: make 'cachetocopy' available in scmutil · 72fdd99e
      Boris Feld authored
      For more code to use this information, we need it to be more publicly available.
      72fdd99e
    • Boris Feld's avatar
      streamclone: add support for cloning non append-only file · 56c30b31
      Boris Feld authored
      The phaseroots are stored in a non append-only file in the repository. We
      include them in the stream too. Since they are not append-only, we have to
      keep a copy around while we hold the lock to be able to stream them later.
      
      Since phase get exchanged within the stream we can skip requesting them
      independently.
      
      As a side effect, this will fixes issue5648 once the feature is enabled by
      default.
      56c30b31
  11. Jan 18, 2018
  12. Jan 17, 2018
    • Boris Feld's avatar
      streamclone: add support for bundle2 based stream clone · 7eedbd5d
      Boris Feld authored
      The feature put to use the various bits introduced previously. If the server
      supports it, the client will request its stream clone through bundle2 instead of
      the legacy 'stream_out' commands. The bundle2 version use the better 'v2'
      version of stream bundles.
      
      The 'v2' format is not finalized yet. Now that there are some code running it,
      we can start working on it again.
      
      Performance numbers are available at the end of this series.
      7eedbd5d
    • Boris Feld's avatar
      pull: preindent some code · 40df727b
      Boris Feld authored
      Next changesets will add support for using stream cloning with bundle2. We
      introduce indentation change first for clarity.
      40df727b
    • Boris Feld's avatar
      pull: reorganize bundle2 argument bundling · 1908d360
      Boris Feld authored
      We are about to add the ability to use stream bundle with bundle2. Before doing
      so, we need to gather some code that will not be used in the bundle2 case. There
      is no behavior change within this changeset.
      1908d360
    • Boris Feld's avatar
      clone: allow bundle2's stream clone with 'server.disablefullbundle' · 133a6786
      Boris Feld authored
      The previous check was a bit too strict and would not recognize a get bundle
      not requesting changegroup.
      133a6786
    • Boris Feld's avatar
      bundle2: add support for a 'stream' parameter to 'getbundle' · c24dad55
      Boris Feld authored
      This parameter can be used to request a stream bundle.
      c24dad55
    • Boris Feld's avatar
      bundle2: add a 'stream' part handler for stream cloning · b996ddf5
      Boris Feld authored
      The part contains the necessary arguments and payload to handle a stream bundle
      v2. It will be put to use in later changesets.
      b996ddf5
    • Boris Feld's avatar
      streamclone: rework canperformstreamclone · bbf7abd0
      Boris Feld authored
      There is code about bundle2 laying around in `canperformstreamclone` but not
      put to any uses. As we discovered with the previous patch, streambundle 'v1'
      won't work on bundle2 because they are readline based. So we jump to 'v2' as
      the first expected supported version.
      bbf7abd0
    • Boris Feld's avatar
      streamclone: define first iteration of version 2 of stream format · cfdccd56
      Boris Feld authored
      (This patch is based on a first draft from Gregory Szorc, with deeper rework)
      
      Version 1 of the stream clone format was invented many years ago and suffers
      from a few deficiencies:
      
      1) Filenames are stored in store-encoded (on filesystem) form rather than in
         their internal form. This makes future compatibility with new store
         filename encodings more difficult.
      2) File entry "headers" consist of a newline of the file name followed by the
         string file size. Converting strings to integers is avoidable overhead. We
         can't store filenames with newlines (manifests have this limitation as
         well, so it isn't a major concern). But the big concern here is the
         necessity for readline(). Scanning for newlines means reading ahead and
         that means extra buffer allocations and slicing (in Python) and this makes
         performance suffer.
      3) Filenames aren't compressed optimally. Filenames should be compressed well
         since there is a lot of repeated data. However, since they are scattered
         all over the stream (with revlog data in between), they typically fall
         outside the window size of the compressor and don't compress.
      4) It can only exchange stored based content, being able to exchange caches
         too would be nice.
      5) It is limited to a stream-based protocol and isn't suitable for an on-disk
         format for general repository reading because the offset of individual file
         entries requires scanning the entire file to find file records.
      
      As part of enabling streaming clones to work in bundle2, #2 proved to have a
      significant negative impact on performance. Since bundle2 provides the
      opportunity to start fresh, Gregory Szorc figured he would take the
      opportunity to invent a new streaming clone data format.
      
      The new format devised in this series addresses #1, #2, and #4. It punts on #3
      because it was complex without yielding a significant gain and on #5 because
      devising a new store format that "packs" multiple revlogs into a single
      "packed revlog" is massive scope bloat. However, this v2 format might be
      suitable for streaming into a "packed revlog" with minimal processing. If it
      works, great. If not, we can always invent stream format when it is needed.
      
      This patch only introduces the bases of the format. We'll get it usable through
      bundle2 first, then we'll extend the format in future patches to bring it to its
      full potential (especially #4).
      cfdccd56
  13. Jan 19, 2018
  14. Jan 20, 2018
  15. Jan 19, 2018
  16. Jan 12, 2018
    • Jörg Sonnenberger's avatar
      wireproto: split streamres into legacy and modern case · a39a9df7
      Jörg Sonnenberger authored
      A couple of commands currently require transmission of uncompressed
      frames with the old MIME type. Split this case from streamres into
      a new streamres_legacy class. Streamline the remaining code accordingly.
      
      Add a new flag to streamres to request uncompressed streams. This is
      useful for sending data that is already compressed like a pre-built
      bundle. Expect clients to support uncompressed data. For older clients,
      zlib will still be used.
      
      Differential Revision: https://phab.mercurial-scm.org/D1862
      a39a9df7
  17. Jan 19, 2018
Loading