Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merlin Pipeline PPX Cache is Broken when a pipeline is only used partially #1647

Closed
dyedgreen opened this issue Jul 4, 2023 · 4 comments · Fixed by ocaml/opam-repository#24310
Labels

Comments

@dyedgreen
Copy link

We’ve run into the following issue with the PPX caching (cc @pitag-ha) in the merlin pipeline:

  1. Construct a pipeline and retrieve only its reader_parsetree
  2. Construct a second pipeline and retrieve its ppx_parsetree or anything that depends on it

Now the PPX stage will return its cached result, because the reader parsetree is cached (from 1.), but the cached result is out of date.

This can be observed in particular when using the ocaml LSP (cc @rgrinberg, @ddickstein), since VSCode will send a documentFoldingRange request which only depends on the parse tree (this then leads to stale errors reported by the LSP, via the cache corruption outlined above).

I think a nice way to solve this issue (at least in the LSP, which has a notion of open documents) would be to remove the implicit global cache and instead have explicit per document caches and pipelines that we construct / update as the documents are opened / changed.

Another way to address this would be to compute a proper digest of the parse tree, rather than doing force_invalidation = not source_is_unmodified.

@voodoos
Copy link
Collaborator

voodoos commented Jul 5, 2023

Here is a more detailed description of the issue as I understand it:

  1. Open a document and make a query that requires the ppx to be run. This populates the reader cache and the ppx cache.
  2. Make an edit to the source.
  3. Run a query that only requires the parsetree. This invalidates the reader cache and repopulate it.
  4. Later, without other changes to the buffer, run a query that does require the ppx. Since the reader cache is correctly populated it will return "no changes" and the obsolete ppx cache will be reused as well.

Is that what you described ?

This is due to the ad-hoc coupling mechanism between the reader and the ppx cache.
I agree with your two suggestions, and added a third one:

  1. Have per-document caches
  2. Use a digest of the parsetree as cache key
  3. Always invalidate the ppx cache when the reader cache is invalidated.

Since there is a bug I think we should first fix it before envisaging a design change like 1. I am wondering what would be the cost of marshaling the parsetree everytime however. Another option could also be to have an integer instead of a boolean value to synchronize the two caches, when the reader result change the integer is bumped. I will have a look.

voodoos added a commit to voodoos/merlin that referenced this issue Jul 5, 2023
@dyedgreen
Copy link
Author

Yes, that description sounds correct to me.

The quick fix we’ve deployed internally so far is to just disable PPX caching entirely, so there is no particular rush for a quick fix from our end / we’d be happy to take time to come up with a new design.

(Although I’m not sure how much this effects the regular merlin protocol / ie if it’s easy to get into that state for most users right now; which might make a quick fix more urgent 😅)

@voodoos
Copy link
Collaborator

voodoos commented Jul 5, 2023

Ok, I was able to reproduce in the test suite and made a fix based on the numbering idea in #1650.

@dyedgreen could you check that is solves your issue ?

@dyedgreen
Copy link
Author

This looks like it should fix the issue I’m seeing!

@voodoos voodoos closed this as completed in a6763da Jul 6, 2023
voodoos added a commit to voodoos/opam-repository that referenced this issue Aug 24, 2023
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
voodoos added a commit to voodoos/opam-repository that referenced this issue Aug 24, 2023
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
voodoos added a commit to voodoos/opam-repository that referenced this issue Aug 24, 2023
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
voodoos added a commit to voodoos/opam-repository that referenced this issue Aug 24, 2023
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
nberth pushed a commit to nberth/opam-repository that referenced this issue Jun 18, 2024
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
nberth pushed a commit to nberth/opam-repository that referenced this issue Jun 18, 2024
CHANGES:

Thu Aug 24 17:17:42 CEST 2023

  + merlin binary
    - Constrain socket path buffer size to avoid build warnings (ocaml/merlin#1631)
    - Handle concurrent server start (ocaml/merlin#1622)
    - Omit module prefixes for constructors and record fields in the
      `construct` command (ocaml/merlin#1618).  Prefixes are still produced when
      warning 42 (disambiguated name) is active.
    - Correctly invalidate PPX cache when pipeline ran partially (ocaml/merlin#1650,
      fixes ocaml/merlin#1647)
    - Prevent `short-path` from looping in some cases related to recursive type
      definitions (ocaml/merlin#1645)
    - Support parsing negative numbers in sexps (ocaml/merlin#1655)
    - Fix construct not working with inline records (ocaml/merlin#1658)
    - Improve behavior of `type-enclosing` on let/and operators (ocaml/merlin#1653)
    - Fix occurrences of extension constructors (ocaml/merlin#1662)
    - Improve node selection when ghosts are present (ocaml/merlin#1664, fixes ocaml/merlin#1660)
  + editor modes
    - emacs: call merlin-client-logger with "interrupted" if the
      merlin binary itself is interrupted, not just the parsing of the
      result (ocaml/merlin#1626).
    - emacs: merlin-construct, with a prefix argument, now includes
      local values in the completion options.  Alternatively, this
      behavior can be enabled permanently by customizing
      `merlin-construct-with-local-values` (ocaml/merlin#1644)
    - emacs: add support for opam-switch-mode (ocaml/merlin#1654, fixes ocaml/merlin#1591).
      See <https://github.com/ProofGeneral/opam-switch-mode>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants