bootsnap 1.4.1-java → 1.4.2-java

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 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