bootsnap 1.4.0 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40694ca2512ff7861584a4f9cee05e424c3d9319f3b36c7f4f45f9196d2d9f19
4
- data.tar.gz: '087c4f2dafdd51a6a3d0a69d31aadabfe6ef90bf2ab12b861f2a288d7b16c04a'
3
+ metadata.gz: be54a60d54f32f824d5c2fdccf189cdcb5409d1848c55f6e654fe44ace1d3f21
4
+ data.tar.gz: c6239c30984a936b76e218c2b1292a7e72d817d3e4847a6c58f0121c1e3068dc
5
5
  SHA512:
6
- metadata.gz: ecbabde06c5f871702a000128e4dbc15d60fe0e16ab7adb4a8bb40b1c3b5b5f54b39c6927dc5aea9e49242d7e7f5deb596c42c44f8c2b8f998f835ec5b058b47
7
- data.tar.gz: d566ffe7c3048f57c3c4fcd925d5e8ff5a722fc2622628e26571361e7a0fbdb5cbe8c724d45f2fc8ba09d0de614c5fad87f1875ecc99a08a34aab3afa7665fe1
6
+ metadata.gz: c251990457406cd51726eec8d62e0e1028bbeade6e24f266cb743d6f00f53650841beed9ee8e1795c78febd18ea234691125920c16aa5a95031718a28619bb31
7
+ data.tar.gz: 554a885bf2264f088618c41864fb84069d0664b35af0ae4b619c8fbb1cf285c80fad564d36845161f8044c35c6b53a33e66f27eb75c6715f25869af2795c97f6
@@ -0,0 +1,2 @@
1
+ # mvm:maintainer
2
+ * @burke
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
data/.travis.yml CHANGED
@@ -17,8 +17,5 @@ matrix:
17
17
  - rvm: jruby
18
18
  os: linux
19
19
  env: MINIMAL_SUPPORT=1
20
- - rvm: truffleruby
21
- os: linux
22
- env: MINIMAL_SUPPORT=1
23
20
 
24
21
  script: bin/ci
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # 1.4.5
2
+
3
+ * MRI 2.7 support
4
+ * Fixed concurrency bugs
5
+
6
+ # 1.4.4
7
+
8
+ * Disable ISeq cache in `bootsnap/setup` by default in Ruby 2.5
9
+
10
+ # 1.4.3
11
+
12
+ * Fix some cache permissions and umask issues after switch to mkstemp
13
+
14
+ # 1.4.2
15
+
16
+ * Fix bug when removing features loaded by relative path from `$LOADED_FEATURES`
17
+ * Fix bug with propagation of `NameError` up from nested calls to `require`
18
+
19
+ # 1.4.1
20
+
21
+ * Don't register change observers to frozen objects.
22
+
1
23
  # 1.4.0
2
24
 
3
25
  * When running in development mode, always fall back to a full path scan on LoadError, making
data/README.md CHANGED
@@ -4,9 +4,14 @@ Bootsnap is a library that plugs into Ruby, with optional support for `ActiveSup
4
4
  to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
5
5
 
6
6
  #### Performance
7
- - [Discourse](https://github.com/discourse/discourse) reports a boot time reduction of approximately 50%, from roughly 6 to 3 seconds on one machine;
7
+
8
+ - [Discourse](https://github.com/discourse/discourse) reports a boot time reduction of approximately
9
+ 50%, from roughly 6 to 3 seconds on one machine;
8
10
  - One of our smaller internal apps also sees a reduction of 50%, from 3.6 to 1.8 seconds;
9
- - The core Shopify platform -- a rather large monolithic application -- boots about 75% faster, dropping from around 25s to 6.5s.
11
+ - The core Shopify platform -- a rather large monolithic application -- boots about 75% faster,
12
+ dropping from around 25s to 6.5s.
13
+ * In Shopify core (a large app), about 25% of this gain can be attributed to `compile_cache_*`
14
+ features; 75% to path caching, and ~1% to `disable_trace`. This is fairly representative.
10
15
 
11
16
  ## Usage
12
17
 
@@ -24,6 +29,14 @@ If you are using Rails, add this to `config/boot.rb` immediately after `require
24
29
  require 'bootsnap/setup'
25
30
  ```
26
31
 
32
+ Note that bootsnap writes to `tmp/cache`, and that directory *must* be writable. Rails will fail to
33
+ boot if it is not. If this is unacceptable (e.g. you are running in a read-only container and
34
+ unwilling to mount in a writable tmpdir), you should remove this line or wrap it in a conditional.
35
+
36
+ **Note also that bootsnap will never clean up its own cache: this is left up to you. Depending on your
37
+ deployment strategy, you may need to periodically purge `tmp/cache/bootsnap*`. If you notice deploys
38
+ getting progressively slower, this is almost certainly the cause.**
39
+
27
40
  It's technically possible to simply specify `gem 'bootsnap', require: 'bootsnap/setup'`, but it's
28
41
  important to load Bootsnap as early as possible to get maximum performance improvement.
29
42
 
@@ -41,12 +54,14 @@ Bootsnap.setup(
41
54
  development_mode: env == 'development', # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
42
55
  load_path_cache: true, # Optimize the LOAD_PATH with a cache
43
56
  autoload_paths_cache: true, # Optimize ActiveSupport autoloads with cache
44
- disable_trace: true, # (Alpha) Set `RubyVM::InstructionSequence.compile_option = { trace_instruction: false }`
57
+ disable_trace: true, # Set `RubyVM::InstructionSequence.compile_option = { trace_instruction: false }`
45
58
  compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
46
59
  compile_cache_yaml: true # Compile YAML into a cache
47
60
  )
48
61
  ```
49
62
 
63
+ **Note that `disable_trace` will break debuggers and tracing.**
64
+
50
65
  **Protip:** You can replace `require 'bootsnap'` with `BootLib::Require.from_gem('bootsnap',
51
66
  'bootsnap')` using [this trick](https://github.com/Shopify/bootsnap/wiki/Bootlib::Require). This
52
67
  will help optimize boot time further if you have an extremely large `$LOAD_PATH`.
@@ -278,3 +293,12 @@ open /c/nope.bundle -> -1
278
293
  ```
279
294
  # (nothing!)
280
295
  ```
296
+
297
+ ## When not to use Bootsnap
298
+
299
+ *Alternative engines*: Bootsnap is pretty reliant on MRI features, and parts are disabled entirely on alternative ruby
300
+ engines.
301
+
302
+ *Non-local filesystems*: Bootsnap depends on `tmp/cache` (or whatever you set its cache directory
303
+ to) being on a relatively fast filesystem. If you put it on a network mount, bootsnap is very likely
304
+ to slow your application down quite a lot.
@@ -74,6 +74,8 @@ static uint32_t current_ruby_platform;
74
74
  static uint32_t current_ruby_revision;
75
75
  /* Invalidates cache when RubyVM::InstructionSequence.compile_option changes */
76
76
  static uint32_t current_compile_option_crc32 = 0;
77
+ /* Current umask */
78
+ static mode_t current_umask;
77
79
 
78
80
  /* Bootsnap::CompileCache::{Native, Uncompilable} */
79
81
  static VALUE rb_mBootsnap;
@@ -94,6 +96,7 @@ static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
94
96
  static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
95
97
  static int open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance);
96
98
  static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance);
99
+ static uint32_t get_ruby_revision(void);
97
100
  static uint32_t get_ruby_platform(void);
98
101
 
99
102
  /*
@@ -134,7 +137,7 @@ Init_bootsnap(void)
134
137
  rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
135
138
  rb_eBootsnap_CompileCache_Uncompilable = rb_define_class_under(rb_mBootsnap_CompileCache, "Uncompilable", rb_eStandardError);
136
139
 
137
- current_ruby_revision = FIX2INT(rb_const_get(rb_cObject, rb_intern("RUBY_REVISION")));
140
+ current_ruby_revision = get_ruby_revision();
138
141
  current_ruby_platform = get_ruby_platform();
139
142
 
140
143
  uncompilable = rb_intern("__bootsnap_uncompilable__");
@@ -142,6 +145,9 @@ Init_bootsnap(void)
142
145
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
143
146
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 3);
144
147
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "compile_option_crc32=", bs_compile_option_crc32_set, 1);
148
+
149
+ current_umask = umask(0777);
150
+ umask(current_umask);
145
151
  }
146
152
 
147
153
  /*
@@ -191,6 +197,26 @@ fnv1a_64(const char *str)
191
197
  return fnv1a_64_iter(h, str);
192
198
  }
193
199
 
200
+ /*
201
+ * Ruby's revision may be Integer or String. CRuby 2.7 or later uses
202
+ * Git commit ID as revision. It's String.
203
+ */
204
+ static uint32_t
205
+ get_ruby_revision(void)
206
+ {
207
+ VALUE ruby_revision;
208
+
209
+ ruby_revision = rb_const_get(rb_cObject, rb_intern("RUBY_REVISION"));
210
+ if (RB_TYPE_P(ruby_revision, RUBY_T_FIXNUM)) {
211
+ return FIX2INT(ruby_revision);
212
+ } else {
213
+ uint64_t hash;
214
+
215
+ hash = fnv1a_64(StringValueCStr(ruby_revision));
216
+ return (uint32_t)(hash >> 32);
217
+ }
218
+ }
219
+
194
220
  /*
195
221
  * When ruby's version doesn't change, but it's recompiled on a different OS
196
222
  * (or OS version), we need to invalidate the cache.
@@ -468,18 +494,17 @@ static int
468
494
  atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
469
495
  {
470
496
  char template[MAX_CACHEPATH_SIZE + 20];
471
- char * dest;
472
497
  char * tmp_path;
473
498
  int fd, ret;
474
499
  ssize_t nwrite;
475
500
 
476
- dest = strncpy(template, path, MAX_CACHEPATH_SIZE);
477
- strcat(dest, ".tmp.XXXXXX");
501
+ tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
502
+ strcat(tmp_path, ".tmp.XXXXXX");
478
503
 
479
- tmp_path = mktemp(template);
480
- fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
504
+ // mkstemp modifies the template to be the actual created path
505
+ fd = mkstemp(tmp_path);
481
506
  if (fd < 0) {
482
- if (mkpath(path, 0775) < 0) {
507
+ if (mkpath(tmp_path, 0775) < 0) {
483
508
  *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
484
509
  return -1;
485
510
  }
@@ -517,6 +542,11 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
517
542
  ret = rename(tmp_path, path);
518
543
  if (ret < 0) {
519
544
  *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:rename";
545
+ return -1;
546
+ }
547
+ ret = chmod(path, 0664 & ~current_umask);
548
+ if (ret < 0) {
549
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:chmod";
520
550
  }
521
551
  return ret;
522
552
  }
@@ -39,6 +39,8 @@ module Bootsnap
39
39
  path.to_s,
40
40
  Bootsnap::CompileCache::ISeq
41
41
  )
42
+ rescue Errno::EACCES
43
+ Bootsnap::CompileCache.permission_error(path)
42
44
  rescue RuntimeError => e
43
45
  if e.message =~ /unmatched platform/
44
46
  puts("unmatched platform for file #{path}")
@@ -46,11 +46,15 @@ module Bootsnap
46
46
 
47
47
  klass = class << ::YAML; self; end
48
48
  klass.send(:define_method, :load_file) do |path|
49
- Bootsnap::CompileCache::Native.fetch(
50
- cache_dir,
51
- path,
52
- Bootsnap::CompileCache::YAML
53
- )
49
+ begin
50
+ Bootsnap::CompileCache::Native.fetch(
51
+ cache_dir,
52
+ path,
53
+ Bootsnap::CompileCache::YAML
54
+ )
55
+ rescue Errno::EACCES
56
+ Bootsnap::CompileCache.permission_error(path)
57
+ end
54
58
  end
55
59
  end
56
60
  end
@@ -1,5 +1,8 @@
1
1
  module Bootsnap
2
2
  module CompileCache
3
+ Error = Class.new(StandardError)
4
+ PermissionError = Class.new(Error)
5
+
3
6
  def self.setup(cache_dir:, iseq:, yaml:)
4
7
  if iseq
5
8
  if supported?
@@ -20,6 +23,15 @@ module Bootsnap
20
23
  end
21
24
  end
22
25
 
26
+ def self.permission_error(path)
27
+ cpath = Bootsnap::CompileCache::ISeq.cache_dir
28
+ raise(
29
+ PermissionError,
30
+ "bootsnap doesn't have permission to write cache entries in '#{cpath}' " \
31
+ "(or, less likely, doesn't have permission to read '#{path}')",
32
+ )
33
+ end
34
+
23
35
  def self.supported?
24
36
  # only enable on 'ruby' (MRI), POSIX (darwin, linux, *bsd), and >= 2.3.0
25
37
  RUBY_ENGINE == 'ruby' &&
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative('../explicit_require')
2
4
 
3
5
  module Bootsnap
@@ -46,7 +48,7 @@ module Bootsnap
46
48
  reinitialize if (@has_relative_paths && dir_changed?) || stale?
47
49
  feature = feature.to_s
48
50
  return feature if absolute_path?(feature)
49
- return File.expand_path(feature) if feature.start_with?('./')
51
+ return expand_path(feature) if feature.start_with?('./')
50
52
  @mutex.synchronize do
51
53
  x = search_index(feature)
52
54
  return x if x
@@ -162,6 +164,10 @@ module Bootsnap
162
164
  end
163
165
  end
164
166
 
167
+ def expand_path(feature)
168
+ maybe_append_extension(File.expand_path(feature))
169
+ end
170
+
165
171
  def stale?
166
172
  @development_mode && @generated_at + AGE_THRESHOLD < now
167
173
  end
@@ -174,10 +180,18 @@ module Bootsnap
174
180
  def search_index(f)
175
181
  try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
176
182
  end
183
+
184
+ def maybe_append_extension(f)
185
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
186
+ end
177
187
  else
178
188
  def search_index(f)
179
189
  try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
180
190
  end
191
+
192
+ def maybe_append_extension(f)
193
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
194
+ end
181
195
  end
182
196
 
183
197
  def try_index(f)
@@ -185,6 +199,10 @@ module Bootsnap
185
199
  p + '/' + f
186
200
  end
187
201
  end
202
+
203
+ def try_ext(f)
204
+ f if File.exist?(f)
205
+ end
188
206
  end
189
207
  end
190
208
  end
@@ -53,6 +53,7 @@ module Bootsnap
53
53
  end
54
54
 
55
55
  def self.register(observer, arr)
56
+ return if arr.frozen? # can't register observer, but no need to.
56
57
  arr.instance_variable_set(:@lpc_observer, observer)
57
58
  arr.extend(ArrayMixin)
58
59
  end
@@ -60,19 +60,22 @@ module Bootsnap
60
60
  super
61
61
  end
62
62
  rescue NameError => e
63
+ raise(e) if e.instance_variable_defined?(Bootsnap::LoadPathCache::ERROR_TAG_IVAR)
64
+ e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
65
+
63
66
  # This function can end up called recursively, we only want to
64
67
  # retry at the top-level.
65
- raise if Thread.current[:without_bootsnap_retry]
68
+ raise(e) if Thread.current[:without_bootsnap_retry]
66
69
  # If we already had cache disabled, there's no use retrying
67
- raise if Thread.current[:without_bootsnap_cache]
70
+ raise(e) if Thread.current[:without_bootsnap_cache]
68
71
  # NoMethodError is a NameError, but we only want to handle actual
69
72
  # NameError instances.
70
- raise unless e.class == NameError
73
+ raise(e) unless e.class == NameError
71
74
  # We can only confidently handle cases when *this* constant fails
72
75
  # to load, not other constants referred to by it.
73
- raise unless e.name == const_name
76
+ raise(e) unless e.name == const_name
74
77
  # If the constant was actually loaded, something else went wrong?
75
- raise if from_mod.const_defined?(const_name)
78
+ raise(e) if from_mod.const_defined?(const_name)
76
79
  CoreExt::ActiveSupport.without_bootsnap_cache { super }
77
80
  end
78
81
 
@@ -80,9 +83,12 @@ module Bootsnap
80
83
  # reiterate it with version polymorphism here...
81
84
  def depend_on(*)
82
85
  super
83
- rescue LoadError
86
+ rescue LoadError => e
87
+ raise(e) if e.instance_variable_defined?(Bootsnap::LoadPathCache::ERROR_TAG_IVAR)
88
+ e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
89
+
84
90
  # If we already had cache disabled, there's no use retrying
85
- raise if Thread.current[:without_bootsnap_cache]
91
+ raise(e) if Thread.current[:without_bootsnap_cache]
86
92
  CoreExt::ActiveSupport.without_bootsnap_cache { super }
87
93
  end
88
94
  end
@@ -3,6 +3,7 @@ module Bootsnap
3
3
  module CoreExt
4
4
  def self.make_load_error(path)
5
5
  err = LoadError.new("cannot load such file -- #{path}")
6
+ err.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
6
7
  err.define_singleton_method(:path) { path }
7
8
  err
8
9
  end
@@ -30,6 +31,9 @@ module Kernel
30
31
  end
31
32
 
32
33
  raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
34
+ rescue LoadError => e
35
+ e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
36
+ raise(e)
33
37
  rescue Bootsnap::LoadPathCache::ReturnFalse
34
38
  false
35
39
  rescue Bootsnap::LoadPathCache::FallbackScan
@@ -56,6 +60,9 @@ module Kernel
56
60
  end
57
61
 
58
62
  raise(Bootsnap::LoadPathCache::CoreExt.make_load_error(path))
63
+ rescue LoadError => e
64
+ e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
65
+ raise(e)
59
66
  rescue Bootsnap::LoadPathCache::ReturnFalse
60
67
  false
61
68
  rescue Bootsnap::LoadPathCache::FallbackScan
@@ -74,6 +81,9 @@ class Module
74
81
  # added to $LOADED_FEATURES and won't be able to hook that modification
75
82
  # since it's done in C-land.
76
83
  autoload_without_bootsnap(const, Bootsnap::LoadPathCache.load_path_cache.find(path) || path)
84
+ rescue LoadError => e
85
+ e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
86
+ raise(e)
77
87
  rescue Bootsnap::LoadPathCache::ReturnFalse
78
88
  false
79
89
  rescue Bootsnap::LoadPathCache::FallbackScan
@@ -4,4 +4,14 @@ class << $LOADED_FEATURES
4
4
  Bootsnap::LoadPathCache.loaded_features_index.purge(key)
5
5
  delete_without_bootsnap(key)
6
6
  end
7
+
8
+ alias_method(:reject_without_bootsnap!, :reject!)
9
+ def reject!(&block)
10
+ backup = dup
11
+
12
+ # FIXME: if no block is passed we'd need to return a decorated iterator
13
+ reject_without_bootsnap!(&block)
14
+
15
+ Bootsnap::LoadPathCache.loaded_features_index.purge_multi(backup - self)
16
+ end
7
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bootsnap
2
4
  module LoadPathCache
3
5
  # LoadedFeaturesIndex partially mirrors an internal structure in ruby that
@@ -55,6 +57,13 @@ module Bootsnap
55
57
  end
56
58
  end
57
59
 
60
+ def purge_multi(features)
61
+ rejected_hashes = features.map(&:hash).to_set
62
+ @mutex.synchronize do
63
+ @lfi.reject! { |_, hash| rejected_hashes.include?(hash) }
64
+ end
65
+ end
66
+
58
67
  def key?(feature)
59
68
  @mutex.synchronize { @lfi.key?(feature) }
60
69
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative('../explicit_require')
2
4
 
3
5
  module Bootsnap
@@ -11,7 +13,7 @@ module Bootsnap
11
13
  BUNDLE_PATH = if Bootsnap.bundler?
12
14
  (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
13
15
  else
14
- ''.freeze
16
+ ''
15
17
  end
16
18
 
17
19
  def self.call(path)
@@ -11,7 +11,8 @@ module Bootsnap
11
11
 
12
12
  def initialize(store_path)
13
13
  @store_path = store_path
14
- @in_txn = false
14
+ # TODO: Remove conditional once Ruby 2.2 support is dropped.
15
+ @txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
15
16
  @dirty = false
16
17
  load_data
17
18
  end
@@ -21,7 +22,7 @@ module Bootsnap
21
22
  end
22
23
 
23
24
  def fetch(key)
24
- raise(SetOutsideTransactionNotAllowed) unless @in_txn
25
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
25
26
  v = get(key)
26
27
  unless v
27
28
  @dirty = true
@@ -32,7 +33,7 @@ module Bootsnap
32
33
  end
33
34
 
34
35
  def set(key, value)
35
- raise(SetOutsideTransactionNotAllowed) unless @in_txn
36
+ raise(SetOutsideTransactionNotAllowed) unless @txn_mutex.owned?
36
37
  if value != @data[key]
37
38
  @dirty = true
38
39
  @data[key] = value
@@ -40,12 +41,14 @@ module Bootsnap
40
41
  end
41
42
 
42
43
  def transaction
43
- raise(NestedTransactionError) if @in_txn
44
- @in_txn = true
45
- yield
46
- ensure
47
- commit_transaction
48
- @in_txn = false
44
+ raise(NestedTransactionError) if @txn_mutex.owned?
45
+ @txn_mutex.synchronize do
46
+ begin
47
+ yield
48
+ ensure
49
+ commit_transaction
50
+ end
51
+ end
49
52
  end
50
53
 
51
54
  private
@@ -60,9 +63,11 @@ module Bootsnap
60
63
  def load_data
61
64
  @data = begin
62
65
  MessagePack.load(File.binread(@store_path))
63
- # handle malformed data due to upgrade incompatability
64
- rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
65
- {}
66
+ # handle malformed data due to upgrade incompatability
67
+ rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
68
+ {}
69
+ rescue ArgumentError => e
70
+ e.message =~ /negative array size/ ? {} : raise
66
71
  end
67
72
  end
68
73
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bootsnap
2
4
  module LoadPathCache
3
5
  ReturnFalse = Class.new(StandardError)
@@ -7,6 +9,11 @@ module Bootsnap
7
9
  DOT_SO = '.so'
8
10
  SLASH = '/'
9
11
 
12
+ # If a NameError happens several levels deep, don't re-handle it
13
+ # all the way up the chain: mark it once and bubble it up without
14
+ # more retries.
15
+ ERROR_TAG_IVAR = :@__bootsnap_rescued
16
+
10
17
  DL_EXTENSIONS = ::RbConfig::CONFIG
11
18
  .values_at('DLEXT', 'DLEXT2')
12
19
  .reject { |ext| !ext || ext.empty? }
@@ -24,12 +24,15 @@ unless cache_dir
24
24
  cache_dir = File.join(app_root, 'tmp', 'cache')
25
25
  end
26
26
 
27
+ ruby_version = Gem::Version.new(RUBY_VERSION)
28
+ iseq_cache_enabled = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.6.0')
29
+
27
30
  Bootsnap.setup(
28
31
  cache_dir: cache_dir,
29
32
  development_mode: development_mode,
30
33
  load_path_cache: true,
31
34
  autoload_paths_cache: true, # assume rails. open to PRs to impl. detection
32
35
  disable_trace: false,
33
- compile_cache_iseq: true,
36
+ compile_cache_iseq: iseq_cache_enabled,
34
37
  compile_cache_yaml: true,
35
38
  )
@@ -1,3 +1,3 @@
1
1
  module Bootsnap
2
- VERSION = "1.4.0"
2
+ VERSION = "1.4.5"
3
3
  end
data/shipit.rubygems.yml CHANGED
@@ -1,4 +0,0 @@
1
- dependencies:
2
- bundler:
3
- without:
4
- - development
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.0
4
+ version: 1.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-11 00:00:00.000000000 Z
11
+ date: 2019-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,6 +102,8 @@ extensions:
102
102
  - ext/bootsnap/extconf.rb
103
103
  extra_rdoc_files: []
104
104
  files:
105
+ - ".github/CODEOWNERS"
106
+ - ".github/probots.yml"
105
107
  - ".gitignore"
106
108
  - ".rubocop.yml"
107
109
  - ".travis.yml"