bootsnap 1.11.1 → 1.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -0
- data/README.md +19 -10
- data/ext/bootsnap/bootsnap.c +225 -113
- data/ext/bootsnap/extconf.rb +20 -13
- data/lib/bootsnap/bundler.rb +1 -1
- data/lib/bootsnap/cli.rb +18 -16
- data/lib/bootsnap/compile_cache/iseq.rb +14 -8
- data/lib/bootsnap/compile_cache/json.rb +18 -17
- data/lib/bootsnap/compile_cache/yaml.rb +46 -60
- data/lib/bootsnap/compile_cache.rb +10 -15
- data/lib/bootsnap/load_path_cache/cache.rb +20 -21
- data/lib/bootsnap/load_path_cache/change_observer.rb +19 -2
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +7 -35
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +2 -2
- data/lib/bootsnap/load_path_cache/path.rb +16 -18
- data/lib/bootsnap/load_path_cache/path_scanner.rb +7 -1
- data/lib/bootsnap/load_path_cache/store.rb +11 -14
- data/lib/bootsnap/load_path_cache.rb +36 -13
- data/lib/bootsnap/setup.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +34 -32
- metadata +4 -4
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "path_scanner"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -35,18 +35,18 @@ module Bootsnap
|
|
35
35
|
return self
|
36
36
|
end
|
37
37
|
|
38
|
-
if realpath
|
39
|
-
Path.new(realpath, real: true)
|
40
|
-
else
|
38
|
+
if realpath == path
|
41
39
|
@real = true
|
42
40
|
self
|
41
|
+
else
|
42
|
+
Path.new(realpath, real: true)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
# True if the path exists, but represents a non-directory object
|
47
47
|
def non_directory?
|
48
48
|
!File.stat(path).directory?
|
49
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
49
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
50
50
|
false
|
51
51
|
end
|
52
52
|
|
@@ -101,7 +101,7 @@ module Bootsnap
|
|
101
101
|
["", *dirs].each do |dir|
|
102
102
|
curr = begin
|
103
103
|
File.mtime("#{path}/#{dir}").to_i
|
104
|
-
rescue Errno::ENOENT, Errno::ENOTDIR
|
104
|
+
rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
|
105
105
|
-1
|
106
106
|
end
|
107
107
|
max = curr if curr > max
|
@@ -116,21 +116,19 @@ module Bootsnap
|
|
116
116
|
VOLATILE = :volatile
|
117
117
|
|
118
118
|
# Built-in ruby lib stuff doesn't change, but things can occasionally be
|
119
|
-
# installed into sitedir, which generally lives under
|
120
|
-
RUBY_LIBDIR = RbConfig::CONFIG["
|
119
|
+
# installed into sitedir, which generally lives under rubylibdir.
|
120
|
+
RUBY_LIBDIR = RbConfig::CONFIG["rubylibdir"]
|
121
121
|
RUBY_SITEDIR = RbConfig::CONFIG["sitedir"]
|
122
122
|
|
123
123
|
def stability
|
124
|
-
@stability ||=
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
VOLATILE
|
133
|
-
end
|
124
|
+
@stability ||= if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
|
125
|
+
STABLE
|
126
|
+
elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
|
127
|
+
STABLE
|
128
|
+
elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
|
129
|
+
STABLE
|
130
|
+
else
|
131
|
+
VOLATILE
|
134
132
|
end
|
135
133
|
end
|
136
134
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
5
|
module Bootsnap
|
6
6
|
module LoadPathCache
|
@@ -15,7 +15,11 @@ module Bootsnap
|
|
15
15
|
""
|
16
16
|
end
|
17
17
|
|
18
|
+
@ignored_directories = %w(node_modules)
|
19
|
+
|
18
20
|
class << self
|
21
|
+
attr_accessor :ignored_directories
|
22
|
+
|
19
23
|
def call(path)
|
20
24
|
path = File.expand_path(path.to_s).freeze
|
21
25
|
return [[], []] unless File.directory?(path)
|
@@ -50,6 +54,8 @@ module Bootsnap
|
|
50
54
|
|
51
55
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
52
56
|
if File.directory?(absolute_path)
|
57
|
+
next if ignored_directories.include?(name) || ignored_directories.include?(absolute_path)
|
58
|
+
|
53
59
|
if yield relative_path, absolute_path, true
|
54
60
|
walk(absolute_path, relative_path, &block)
|
55
61
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "../explicit_require"
|
4
4
|
|
5
|
-
Bootsnap::ExplicitRequire.with_gems("msgpack") { require
|
5
|
+
Bootsnap::ExplicitRequire.with_gems("msgpack") { require "msgpack" }
|
6
6
|
|
7
7
|
module Bootsnap
|
8
8
|
module LoadPathCache
|
@@ -13,10 +13,11 @@ module Bootsnap
|
|
13
13
|
NestedTransactionError = Class.new(StandardError)
|
14
14
|
SetOutsideTransactionNotAllowed = Class.new(StandardError)
|
15
15
|
|
16
|
-
def initialize(store_path)
|
16
|
+
def initialize(store_path, readonly: false)
|
17
17
|
@store_path = store_path
|
18
18
|
@txn_mutex = Mutex.new
|
19
19
|
@dirty = false
|
20
|
+
@readonly = readonly
|
20
21
|
load_data
|
21
22
|
end
|
22
23
|
|
@@ -49,11 +50,9 @@ module Bootsnap
|
|
49
50
|
raise(NestedTransactionError) if @txn_mutex.owned?
|
50
51
|
|
51
52
|
@txn_mutex.synchronize do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
commit_transaction
|
56
|
-
end
|
53
|
+
yield
|
54
|
+
ensure
|
55
|
+
commit_transaction
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
@@ -65,7 +64,7 @@ module Bootsnap
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def commit_transaction
|
68
|
-
if @dirty
|
67
|
+
if @dirty && !@readonly
|
69
68
|
dump_data
|
70
69
|
@dirty = false
|
71
70
|
end
|
@@ -121,11 +120,9 @@ module Bootsnap
|
|
121
120
|
path = File.dirname(path)
|
122
121
|
end
|
123
122
|
stack.reverse_each do |dir|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
raise unless File.directory?(dir)
|
128
|
-
end
|
123
|
+
Dir.mkdir(dir)
|
124
|
+
rescue SystemCallError
|
125
|
+
raise unless File.directory?(dir)
|
129
126
|
end
|
130
127
|
end
|
131
128
|
end
|
@@ -21,37 +21,60 @@ module Bootsnap
|
|
21
21
|
|
22
22
|
CACHED_EXTENSIONS = DLEXT2 ? [DOT_RB, DLEXT, DLEXT2] : [DOT_RB, DLEXT]
|
23
23
|
|
24
|
+
@enabled = false
|
25
|
+
|
24
26
|
class << self
|
25
|
-
attr_reader(:load_path_cache, :loaded_features_index)
|
27
|
+
attr_reader(:load_path_cache, :loaded_features_index, :enabled)
|
28
|
+
alias_method :enabled?, :enabled
|
29
|
+
remove_method(:enabled)
|
26
30
|
|
27
|
-
def setup(cache_path:, development_mode:)
|
31
|
+
def setup(cache_path:, development_mode:, ignore_directories:, readonly: false)
|
28
32
|
unless supported?
|
29
33
|
warn("[bootsnap/setup] Load path caching is not supported on this implementation of Ruby") if $VERBOSE
|
30
34
|
return
|
31
35
|
end
|
32
36
|
|
33
|
-
store = Store.new(cache_path)
|
37
|
+
store = Store.new(cache_path, readonly: readonly)
|
34
38
|
|
35
39
|
@loaded_features_index = LoadedFeaturesIndex.new
|
36
40
|
|
41
|
+
PathScanner.ignored_directories = ignore_directories if ignore_directories
|
37
42
|
@load_path_cache = Cache.new(store, $LOAD_PATH, development_mode: development_mode)
|
38
|
-
|
39
|
-
require_relative
|
43
|
+
@enabled = true
|
44
|
+
require_relative "load_path_cache/core_ext/kernel_require"
|
45
|
+
require_relative "load_path_cache/core_ext/loaded_features"
|
46
|
+
end
|
47
|
+
|
48
|
+
def unload!
|
49
|
+
@enabled = false
|
50
|
+
@loaded_features_index = nil
|
51
|
+
@realpath_cache = nil
|
52
|
+
@load_path_cache = nil
|
53
|
+
ChangeObserver.unregister($LOAD_PATH) if supported?
|
40
54
|
end
|
41
55
|
|
42
56
|
def supported?
|
43
|
-
|
44
|
-
|
57
|
+
if RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
|
58
|
+
case RUBY_ENGINE
|
59
|
+
when "truffleruby"
|
60
|
+
# https://github.com/oracle/truffleruby/issues/3131
|
61
|
+
RUBY_ENGINE_VERSION >= "23.1.0"
|
62
|
+
when "ruby"
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
45
68
|
end
|
46
69
|
end
|
47
70
|
end
|
48
71
|
end
|
49
72
|
|
50
73
|
if Bootsnap::LoadPathCache.supported?
|
51
|
-
require_relative
|
52
|
-
require_relative
|
53
|
-
require_relative
|
54
|
-
require_relative
|
55
|
-
require_relative
|
56
|
-
require_relative
|
74
|
+
require_relative "load_path_cache/path_scanner"
|
75
|
+
require_relative "load_path_cache/path"
|
76
|
+
require_relative "load_path_cache/cache"
|
77
|
+
require_relative "load_path_cache/store"
|
78
|
+
require_relative "load_path_cache/change_observer"
|
79
|
+
require_relative "load_path_cache/loaded_features_index"
|
57
80
|
end
|
data/lib/bootsnap/setup.rb
CHANGED
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
3
|
+
require_relative "bootsnap/version"
|
4
|
+
require_relative "bootsnap/bundler"
|
5
|
+
require_relative "bootsnap/load_path_cache"
|
6
|
+
require_relative "bootsnap/compile_cache"
|
7
7
|
|
8
8
|
module Bootsnap
|
9
9
|
InvalidConfiguration = Class.new(StandardError)
|
@@ -11,6 +11,16 @@ module Bootsnap
|
|
11
11
|
class << self
|
12
12
|
attr_reader :logger
|
13
13
|
|
14
|
+
def log_stats!
|
15
|
+
stats = {hit: 0, revalidated: 0, miss: 0, stale: 0}
|
16
|
+
self.instrumentation = ->(event, _path) { stats[event] += 1 }
|
17
|
+
Kernel.at_exit do
|
18
|
+
stats.each do |event, count|
|
19
|
+
$stderr.puts "bootsnap #{event}: #{count}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
def log!
|
15
25
|
self.logger = $stderr.method(:puts)
|
16
26
|
end
|
@@ -18,9 +28,9 @@ module Bootsnap
|
|
18
28
|
def logger=(logger)
|
19
29
|
@logger = logger
|
20
30
|
self.instrumentation = if logger.respond_to?(:debug)
|
21
|
-
->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") }
|
31
|
+
->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") unless event == :hit }
|
22
32
|
else
|
23
|
-
->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") }
|
33
|
+
->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") unless event == :hit }
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
@@ -39,48 +49,32 @@ module Bootsnap
|
|
39
49
|
cache_dir:,
|
40
50
|
development_mode: true,
|
41
51
|
load_path_cache: true,
|
42
|
-
|
43
|
-
|
52
|
+
ignore_directories: nil,
|
53
|
+
readonly: false,
|
44
54
|
compile_cache_iseq: true,
|
45
55
|
compile_cache_yaml: true,
|
46
56
|
compile_cache_json: true
|
47
57
|
)
|
48
|
-
unless autoload_paths_cache.nil?
|
49
|
-
warn "[DEPRECATED] Bootsnap's `autoload_paths_cache:` option is deprecated and will be removed. " \
|
50
|
-
"If you use Zeitwerk this option is useless, and if you are still using the classic autoloader " \
|
51
|
-
"upgrading is recommended."
|
52
|
-
end
|
53
|
-
|
54
|
-
unless disable_trace.nil?
|
55
|
-
warn "[DEPRECATED] Bootsnap's `disable_trace:` option is deprecated and will be removed. " \
|
56
|
-
"If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
|
57
|
-
end
|
58
|
-
|
59
|
-
if compile_cache_iseq && !iseq_cache_supported?
|
60
|
-
warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
|
61
|
-
"to turn `compile_cache_iseq` off on Ruby 2.5"
|
62
|
-
end
|
63
|
-
|
64
58
|
if load_path_cache
|
65
59
|
Bootsnap::LoadPathCache.setup(
|
66
|
-
cache_path: cache_dir
|
60
|
+
cache_path: "#{cache_dir}/bootsnap/load-path-cache",
|
67
61
|
development_mode: development_mode,
|
62
|
+
ignore_directories: ignore_directories,
|
63
|
+
readonly: readonly,
|
68
64
|
)
|
69
65
|
end
|
70
66
|
|
71
67
|
Bootsnap::CompileCache.setup(
|
72
|
-
cache_dir: cache_dir
|
68
|
+
cache_dir: "#{cache_dir}/bootsnap/compile-cache",
|
73
69
|
iseq: compile_cache_iseq,
|
74
70
|
yaml: compile_cache_yaml,
|
75
71
|
json: compile_cache_json,
|
72
|
+
readonly: readonly,
|
76
73
|
)
|
77
74
|
end
|
78
75
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
ruby_version = Gem::Version.new(RUBY_VERSION)
|
83
|
-
@iseq_cache_supported = ruby_version < Gem::Version.new("2.5.0") || ruby_version >= Gem::Version.new("2.6.0")
|
76
|
+
def unload_cache!
|
77
|
+
LoadPathCache.unload!
|
84
78
|
end
|
85
79
|
|
86
80
|
def default_setup
|
@@ -109,17 +103,25 @@ module Bootsnap
|
|
109
103
|
cache_dir = File.join(app_root, "tmp", "cache")
|
110
104
|
end
|
111
105
|
|
106
|
+
ignore_directories = if ENV.key?("BOOTSNAP_IGNORE_DIRECTORIES")
|
107
|
+
ENV["BOOTSNAP_IGNORE_DIRECTORIES"].split(",")
|
108
|
+
end
|
109
|
+
|
112
110
|
setup(
|
113
111
|
cache_dir: cache_dir,
|
114
112
|
development_mode: development_mode,
|
115
113
|
load_path_cache: !ENV["DISABLE_BOOTSNAP_LOAD_PATH_CACHE"],
|
116
|
-
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"]
|
114
|
+
compile_cache_iseq: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
117
115
|
compile_cache_yaml: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
118
116
|
compile_cache_json: !ENV["DISABLE_BOOTSNAP_COMPILE_CACHE"],
|
117
|
+
readonly: !!ENV["BOOTSNAP_READONLY"],
|
118
|
+
ignore_directories: ignore_directories,
|
119
119
|
)
|
120
120
|
|
121
121
|
if ENV["BOOTSNAP_LOG"]
|
122
122
|
log!
|
123
|
+
elsif ENV["BOOTSNAP_STATS"]
|
124
|
+
log_stats!
|
123
125
|
end
|
124
126
|
end
|
125
127
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootsnap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.18.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -76,14 +76,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
76
|
requirements:
|
77
77
|
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: 2.
|
79
|
+
version: 2.6.0
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
86
|
+
rubygems_version: 3.5.5
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
89
|
summary: Boot large ruby/rails apps faster
|