Skip to content

Commit

Permalink
Merge pull request #387 from Shopify/load-path-cache-version
Browse files Browse the repository at this point in the history
Ignore load path caches generated by a different ruby version
  • Loading branch information
casperisfine committed Jan 10, 2022
2 parents a0aa3d2 + 8726b29 commit 728845d
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
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

0 comments on commit 728845d

Please sign in to comment.