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

Ignore load path caches generated by a different ruby version #387

Merged
merged 1 commit into from Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,8 @@
# Unreleased

* Automatically invalidate the load path cache whenever the Ruby version change. (#387)
This is to avoid issues in case the same installation path is re-used for subsequent ruby patch releases.

# 1.9.3

* Only disable the compile cache for source files impacted by [Ruby 3.0.3 [Bug 18250]](https://bugs.ruby-lang.org/issues/18250).
Expand Down
18 changes: 15 additions & 3 deletions lib/bootsnap/load_path_cache/store.rb
Expand Up @@ -7,6 +7,9 @@
module Bootsnap
module LoadPathCache
class Store
VERSION_KEY = '__bootsnap_ruby_version__'
CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze

NestedTransactionError = Class.new(StandardError)
SetOutsideTransactionNotAllowed = Class.new(StandardError)

Expand Down Expand Up @@ -62,15 +65,20 @@ def commit_transaction

def load_data
@data = begin
File.open(@store_path, encoding: Encoding::BINARY) do |io|
data = File.open(@store_path, encoding: Encoding::BINARY) do |io|
MessagePack.load(io)
end
if data.is_a?(Hash) && data[VERSION_KEY] == CURRENT_VERSION
data
else
default_data
end
# handle malformed data due to upgrade incompatibility
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
{}
default_data
rescue ArgumentError => error
if error.message =~ /negative array size/
{}
default_data
else
raise
end
Expand All @@ -93,6 +101,10 @@ def dump_data
retry
rescue SystemCallError
end

def default_data
{ VERSION_KEY => CURRENT_VERSION }
end
end
end
end
24 changes: 24 additions & 0 deletions test/load_path_cache/store_test.rb
Expand Up @@ -80,6 +80,30 @@ def test_ignore_read_only_filesystem
store.transaction { store.set('a', 1) }
refute(File.exist?(@path))
end

def test_bust_cache_on_ruby_change
store.transaction { store.set('a', 'b') }

assert_equal 'b', Store.new(@path).get('a')

stub_const(Store, :CURRENT_VERSION, "foobar") do
assert_nil Store.new(@path).get('a')
end
end

private

def stub_const(owner, const_name, stub_value)
original_value = owner.const_get(const_name)
owner.send(:remove_const, const_name)
owner.const_set(const_name, stub_value)
begin
yield
ensure
owner.send(:remove_const, const_name)
owner.const_set(const_name, original_value)
end
end
end
end
end