bootsnap 1.4.1 → 1.4.2.rc1

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: 0ecf22c8b6dc4b98a6f7ac7fe451d3bc7e2d29893c2bc8e9428b0143997e739a
4
- data.tar.gz: a57576a6e84953b44bf245e4e43e18a8a2a457a18fe5eb3688e066e9fe893c2c
3
+ metadata.gz: 1b7e391a76fc9fe8cc2c712d7623f26e6138f24c62acd3cd16a470f50812e554
4
+ data.tar.gz: 23d068050fd8c1962915608e73418c01dc568cc5371a5d27f77a269ef2926aeb
5
5
  SHA512:
6
- metadata.gz: '005135654997ebaea3f0975bbc7be897b5d40eaaebec11573709ce83574f2131987441f103e795d45d7c83a4517ede8764e0a43c5e00cb53e84c8e498d9475e7'
7
- data.tar.gz: 85cc529d70ec6318d30f1edba6cbed627276ee3c7fb200096960a3cd08a953ad0f018601bf223d0a5216b981edd07c3fa9b54b3192daa8881e0625c2d4f7fa11
6
+ metadata.gz: 815c87a26099673845b530d5a0bb2000ceda89f15a17eeca178b087d3ae4af6230ce8dcaa15a4360a2fdb0fc8d923d0659dc47ac6a7d2b072d43eebadeaebc79
7
+ data.tar.gz: 46584a5b22e3a64a02302a3ea87dfbe6e99676935838560ec93f938a0c3b86e854aacd48364e4f7161c021d5472497844b3d81074e1a3cc1be82a2aac3bee158
@@ -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,8 @@
1
+ # 1.4.2
2
+
3
+ * Fix bug when removing features loaded by relative path from `$LOADED_FEATURES`
4
+ * Fix bug with propagation of `NameError` up from nested calls to `require`
5
+
1
6
  # 1.4.1
2
7
 
3
8
  * Don't register change observers to frozen objects.
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
 
@@ -284,3 +289,12 @@ open /c/nope.bundle -> -1
284
289
  ```
285
290
  # (nothing!)
286
291
  ```
292
+
293
+ ## When not to use Bootsnap
294
+
295
+ *Alternative engines*: Bootsnap is pretty reliant on MRI features, and parts are disabled entirely on alternative ruby
296
+ engines.
297
+
298
+ *Non-local filesystems*: Bootsnap depends on `tmp/cache` (or whatever you set its cache directory
299
+ to) being on a relatively fast filesystem. If you put it on a network mount, bootsnap is very likely
300
+ to slow your application down quite a lot.
@@ -468,21 +468,21 @@ static int
468
468
  atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
469
469
  {
470
470
  char template[MAX_CACHEPATH_SIZE + 20];
471
- char * dest;
472
471
  char * tmp_path;
473
472
  int fd, ret;
474
473
  ssize_t nwrite;
475
474
 
476
- dest = strncpy(template, path, MAX_CACHEPATH_SIZE);
477
- strcat(dest, ".tmp.XXXXXX");
475
+ tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
476
+ strcat(tmp_path, ".tmp.XXXXXX");
478
477
 
479
- tmp_path = mktemp(template);
480
- fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
478
+ // mkstemp modifies the template to be the actual created path
479
+ fd = mkstemp(tmp_path);
481
480
  if (fd < 0) {
482
- if (mkpath(path, 0775) < 0) {
481
+ if (mkpath(tmp_path, 0775) < 0) {
483
482
  *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
484
483
  return -1;
485
484
  }
485
+ close(fd);
486
486
  fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
487
487
  if (fd < 0) {
488
488
  *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:open";
@@ -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 permisison 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' &&
@@ -46,7 +46,7 @@ module Bootsnap
46
46
  reinitialize if (@has_relative_paths && dir_changed?) || stale?
47
47
  feature = feature.to_s
48
48
  return feature if absolute_path?(feature)
49
- return File.expand_path(feature) if feature.start_with?('./')
49
+ return expand_path(feature) if feature.start_with?('./')
50
50
  @mutex.synchronize do
51
51
  x = search_index(feature)
52
52
  return x if x
@@ -162,6 +162,10 @@ module Bootsnap
162
162
  end
163
163
  end
164
164
 
165
+ def expand_path(feature)
166
+ maybe_append_extension(File.expand_path(feature))
167
+ end
168
+
165
169
  def stale?
166
170
  @development_mode && @generated_at + AGE_THRESHOLD < now
167
171
  end
@@ -174,10 +178,18 @@ module Bootsnap
174
178
  def search_index(f)
175
179
  try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
176
180
  end
181
+
182
+ def maybe_append_extension(f)
183
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
184
+ end
177
185
  else
178
186
  def search_index(f)
179
187
  try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
180
188
  end
189
+
190
+ def maybe_append_extension(f)
191
+ try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
192
+ end
181
193
  end
182
194
 
183
195
  def try_index(f)
@@ -185,6 +197,10 @@ module Bootsnap
185
197
  p + '/' + f
186
198
  end
187
199
  end
200
+
201
+ def try_ext(f)
202
+ f if File.exist?(f)
203
+ end
188
204
  end
189
205
  end
190
206
  end
@@ -18,6 +18,11 @@ module Bootsnap
18
18
  Thread.current[:without_bootsnap_retry] = prev
19
19
  end
20
20
 
21
+ # If a NameError happens several levels deep, don't re-handle it
22
+ # all the way up the chain: mark it once and bubble it up without
23
+ # more retries.
24
+ ERROR_TAG_IVAR = :@__bootsnap_rescued
25
+
21
26
  module ClassMethods
22
27
  def autoload_paths=(o)
23
28
  super
@@ -60,19 +65,22 @@ module Bootsnap
60
65
  super
61
66
  end
62
67
  rescue NameError => e
68
+ raise(e) if e.instance_variable_defined?(ERROR_TAG_IVAR)
69
+ e.instance_variable_set(ERROR_TAG_IVAR, true)
70
+
63
71
  # This function can end up called recursively, we only want to
64
72
  # retry at the top-level.
65
- raise if Thread.current[:without_bootsnap_retry]
73
+ raise(e) if Thread.current[:without_bootsnap_retry]
66
74
  # If we already had cache disabled, there's no use retrying
67
- raise if Thread.current[:without_bootsnap_cache]
75
+ raise(e) if Thread.current[:without_bootsnap_cache]
68
76
  # NoMethodError is a NameError, but we only want to handle actual
69
77
  # NameError instances.
70
- raise unless e.class == NameError
78
+ raise(e) unless e.class == NameError
71
79
  # We can only confidently handle cases when *this* constant fails
72
80
  # to load, not other constants referred to by it.
73
- raise unless e.name == const_name
81
+ raise(e) unless e.name == const_name
74
82
  # If the constant was actually loaded, something else went wrong?
75
- raise if from_mod.const_defined?(const_name)
83
+ raise(e) if from_mod.const_defined?(const_name)
76
84
  CoreExt::ActiveSupport.without_bootsnap_cache { super }
77
85
  end
78
86
 
@@ -80,9 +88,12 @@ module Bootsnap
80
88
  # reiterate it with version polymorphism here...
81
89
  def depend_on(*)
82
90
  super
83
- rescue LoadError
91
+ rescue LoadError => e
92
+ raise(e) if e.instance_variable_defined?(ERROR_TAG_IVAR)
93
+ e.instance_variable_set(ERROR_TAG_IVAR, true)
94
+
84
95
  # If we already had cache disabled, there's no use retrying
85
- raise if Thread.current[:without_bootsnap_cache]
96
+ raise(e) if Thread.current[:without_bootsnap_cache]
86
97
  CoreExt::ActiveSupport.without_bootsnap_cache { super }
87
98
  end
88
99
  end
@@ -60,9 +60,11 @@ module Bootsnap
60
60
  def load_data
61
61
  @data = begin
62
62
  MessagePack.load(File.binread(@store_path))
63
- # handle malformed data due to upgrade incompatability
64
- rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
65
- {}
63
+ # handle malformed data due to upgrade incompatability
64
+ rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
65
+ {}
66
+ rescue ArgumentError => e
67
+ e.message =~ /negative array size/ ? {} : raise
66
68
  end
67
69
  end
68
70
 
@@ -1,3 +1,3 @@
1
1
  module Bootsnap
2
- VERSION = "1.4.1"
2
+ VERSION = "1.4.2.rc1"
3
3
  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.1
4
+ version: 1.4.2.rc1
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-25 00:00:00.000000000 Z
11
+ date: 2019-03-20 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"
@@ -161,12 +163,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
163
  version: 2.0.0
162
164
  required_rubygems_version: !ruby/object:Gem::Requirement
163
165
  requirements:
164
- - - ">="
166
+ - - ">"
165
167
  - !ruby/object:Gem::Version
166
- version: '0'
168
+ version: 1.3.1
167
169
  requirements: []
168
- rubyforge_project:
169
- rubygems_version: 2.7.6
170
+ rubygems_version: 3.0.2
170
171
  signing_key:
171
172
  specification_version: 4
172
173
  summary: Boot large ruby/rails apps faster