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

IfFileExists incorrectly caches results #1571

Open
spakin opened this issue Dec 2, 2024 · 10 comments
Open

IfFileExists incorrectly caches results #1571

spakin opened this issue Dec 2, 2024 · 10 comments

Comments

@spakin
Copy link

spakin commented Dec 2, 2024

Brief outline of the bug

Once \IfFileExists determines that a file exists, it remembers this fact and subsequently neglects to check if the file has ceased to exist.

Minimal example showing the bug

Run with LuaLaTeX:

\RequirePackage{latexbug}
\documentclass{article}

\begin{document}

\IfFileExists{\jobname.zzz}{YES}{NO}

\begin{filecontents}{\jobname.zzz}
This file will be deleted.
\end{filecontents}

\IfFileExists{\jobname.zzz}{YES}{NO}

\directlua{os.remove('\jobname.zzz')}

\IfFileExists{\jobname.zzz}{YES}{NO}

\end{document}

(Derived from @davidcarlisle's answer to https://tex.stackexchange.com/questions/611391/delete-a-file-using-luacode.)

  • The first \IfFileExists should typeset NO (assuming you don't have the .zzz file it's looking for).
  • The second \IfFileExists should typeset YES because the code used a filecontents environment to create the .zzz file.
  • The third \IfFileExists should typeset NO because the code deleted the .zzz file using Lua's os.remove function. However, because \IfFileExists incorrectly remembers the previous true path it takes that path again and erroneously outputs YES.

Log file (required) and possibly PDF file

iffileexists.log
iffileexists.pdf

Possible solution

I'm no LaTeX3 expert, but it looks to me like the caching may originate in \__file_full_name_aux:n. Perhaps retaining only the false path will solve the problem?

\cs_new:Npn \__file_full_name_aux:n #1
  {
    \exp_args:Ne \__file_full_name_auxi:nn { \__file_size:n {#1} } {#1}
  }
@josephwright
Copy link
Member

Caching here is by-design - file operations are slow, and thus looking up a file's existence multiple times is not desirable. The working assumption for a (La)TeX run is that as a batch process, if files exist at the start of the run, they will be available throughout.

@josephwright
Copy link
Member

Code comment in l3file covers this

%   To avoid repeated reading of files we need to cache the loading:
%   this is important as the code here is used by \emph{all} file checks.
%   The same marker is used in the \LaTeXe{} kernel, meaning that we get a
%   double-saving with for example \cs{IfFileExists}. As this is all about
%   performance, we use the low-level approach for the conditionals. For
%   a file already seen, the size is reported as $-1$ so it's distinct from
%   any non-cached ones.

@muzimuzhi
Copy link
Contributor

BTW, it's a relatively new feature, introduced in the 2023-06-01 release. See texdoc ltnews37, sec. "Performance in checking file existence".

\subsection{Performance in checking file existence}
The addition of hooks, etc., to file operations had a side effect of making
multiple checks that the file existed. In larger documents using
many files, these file system operations caused non-trivial performance
impact. We now cache the existence of files, such that these repeated filesystem
calls are avoided.

@spakin
Copy link
Author

spakin commented Dec 2, 2024

I see. Would it be a nontrivial change to support cache bypass as an option to \IfFileExists—defaulting to file existence being cached—for use in cases where files come and go (as mimicked by my MWE)?

If that would be difficult to add to LaTeX3, I'll copy over (and rename) the simpler, more straightforward LaTeX2ε implementation of \IfFileExists and use that in my code.

@josephwright
Copy link
Member

@spakin I've just added latex3/latex3#1635 to the expl3 side of things, and we will sort an interface for this for the June 2025 LaTeX release - the expl3 code iwll likely be released mid-January to support this.

@josephwright
Copy link
Member

@spakin If you need a temporary hack, use

\ExplSyntaxOn
\cs_gset_protected:Npn \file_forget:n #1
  { \cs_undefine:c { __file_seen_ \file_full_name:n {#1} : } }
\ExplSyntaxOff

in the preamble then

\ExplSyntaxOn
\file_forget:n {<name>}
\ExplSyntaxOff

at the point you delete the file.

@spakin
Copy link
Author

spakin commented Dec 11, 2024

@josephwright: Thanks for writing latex3/latex3#1635 and for providing a temporary hack. Much appreciated.

@FrankMittelbach
Copy link
Member

Scott, the team has decided to offer that interface only on the L3 layer level so \file_forget:n {<name>} will be available with the next upload of the l3kernel code but the 2e side will not get any CamelCase name for it in June. The rationale is that 2e doesn't have any interfaces for deleting files so any code doing this needs low-level coding.

@josephwright
Copy link
Member

If we want \file_forget:n in the next release, I should do an extra dev release - can sort today

@FrankMittelbach
Copy link
Member

FrankMittelbach commented Dec 11, 2024

I thought that would happen rather automatically any time soon, eg when you prepare a new upload to ctan. I meant the one you hinted at for January. I don't think it really needs to be earlier just for that (only means extra work for the CTAN maintainers).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants