Skip to content

Avoid recreating cache files removed during a read - #839

Open
OskarEichler wants to merge 1 commit into
rails:mainfrom
OskarEichler:codex/eviction-cache-fix
Open

Avoid recreating cache files removed during a read#839
OskarEichler wants to merge 1 commit into
rails:mainfrom
OskarEichler:codex/eviction-cache-fix

Conversation

@OskarEichler

Copy link
Copy Markdown

Summary

A file cache read may finish after another process evicts that entry; updating its access time does not recreate an empty cache file.

File.utime does not recreate files. Only ENOENT from that operation is ignored. The already-read value is returned. General cross-process atomicity and unrelated Windows atomic-write issue #136/#773 are not addressed.

Reproduction

With require "sprockets"; require "tmpdir":

Dir.mktmpdir do |dir|
  store = Sprockets::Cache::FileStore.new(dir)
  store.set("entry", "content")
  store.define_singleton_method(:safe_open) do |path, &block|
    value = super(path, &block)
    File.unlink(path) # model eviction after reading
    value
  end
  p store.get("entry") # "content"
  p File.exist?(File.join(dir, "entry.cache")) # false; previously an empty file
end

Verification

  • Original behavior reproduced on release 4.4.1/current main (49d9f20c00ac7d9a7ee57db058961edcccd86699).
  • This isolated patch passes unchanged bundle exec rake test: 913 tests / 4,109 assertions / zero failures/errors / four skips on Ruby 3.2.11 and 4.0.6. 25 focused external checks pass per Ruby.
  • Combined six cache fixes also pass the full suite and rake test_isolated on both Rubies, plus 396 focused checks. Normal skips cover Windows-only, legacy-Ruby and two Sass compatibility cases. Non-terminal stdin additionally skips the Unix device check (4,107 assertions).
  • Full RuboCop passes 133 files. Gem build preserves 84 package paths, version 4.4.1, Ruby >=2.5 and dependency requirements. All runtime files pass Ruby 3.2/4.0 syntax checks; diff whitespace checked.
  • No test files added or edited under the consumer repository's no-test-edit policy. Reproductions and additional checks were run externally.

Compatibility and limitations

Breaking changes: none intended. The incorrect behavior above changes. No public signature, dependency, serialized cache format or version changes. Older supported Rubies, JRuby and Linux are not claimed locally verified. This is a focused cache correction, not a completed review of all Sprockets behavior. Prepared with AI assistance; results above are from actual local runs.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant