bootsnap 1.4.1-java → 1.4.2-java

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
- SHA256:
3
- metadata.gz: bbe2d60be7b9970d1b993f144e28071bf85ebb528f24df8afbc00e5f4a1df6da
4
- data.tar.gz: 2cda0fdec14bcedf1c6e232e75380ee7cabbdec2953428912563a83c39bb9472
2
+ SHA1:
3
+ metadata.gz: 4e355bad836c2faeacff354f3b026f03401171c4
4
+ data.tar.gz: 89cb1e0c808975099905f5ba9a7ee7cea58e9338
5
5
  SHA512:
6
- metadata.gz: 1b8b3cb9986921f82c8c3489c37e33a576587d93ef09fc94b5c7e16e6682d86c54283b34bc659b2a5f1bb60f14d2c1ae272ef2e4a3089d623a36e6e4529c5629
7
- data.tar.gz: 85efef308c58141634984fbda14d393f7555333456c57b99e10ae7f8ddc592c3623cbefd0ffc34c2217092407014667dad3744b4b86d367a0f91a82df3f9853c
6
+ metadata.gz: bc454087a30b54b6735ba8c8640f640261a5cd5f232fec2edf53438b868e74ef8e178bcd03e5a083f46188e5049776bbf4e3981cc7fea13927d24081e94f1cdf
7
+ data.tar.gz: 234c23ed91b2632db1bddae904a3d0c319016e84616172d9aaed0a666188ceeca9803d2f6d85f642a7917815fc094f352645938cd4b9f2fa9136658d137b2314
@@ -0,0 +1,2 @@
1
+ # mvm:maintainer
2
+ * @burke
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
@@ -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
@@ -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
 
@@ -28,6 +33,10 @@ Note that bootsnap writes to `tmp/cache`, and that directory *must* be writable.
28
33
  boot if it is not. If this is unacceptable (e.g. you are running in a read-only container and
29
34
  unwilling to mount in a writable tmpdir), you should remove this line or wrap it in a conditional.
30
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
+
31
40
  It's technically possible to simply specify `gem 'bootsnap', require: 'bootsnap/setup'`, but it's
32
41
  important to load Bootsnap as early as possible to get maximum performance improvement.
33
42
 
@@ -284,3 +293,12 @@ open /c/nope.bundle -> -1
284
293
  ```
285
294
  # (nothing!)
286
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.
@@ -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";
@@ -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' &&
@@ -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,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? }
@@ -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
@@ -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)
@@ -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"
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
5
5
  platform: java
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-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +101,8 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - ".github/CODEOWNERS"
105
+ - ".github/probots.yml"
104
106
  - ".gitignore"
105
107
  - ".rubocop.yml"
106
108
  - ".travis.yml"
@@ -165,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
167
  version: '0'
166
168
  requirements: []
167
169
  rubyforge_project:
168
- rubygems_version: 2.7.6
170
+ rubygems_version: 2.4.8
169
171
  signing_key:
170
172
  specification_version: 4
171
173
  summary: Boot large ruby/rails apps faster