bootsnap 1.7.0 → 1.7.4
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 +20 -0
- data/ext/bootsnap/bootsnap.c +31 -17
- data/ext/bootsnap/extconf.rb +19 -14
- data/lib/bootsnap.rb +13 -3
- data/lib/bootsnap/compile_cache/yaml.rb +37 -17
- data/lib/bootsnap/load_path_cache/cache.rb +26 -9
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +1 -1
- data/lib/bootsnap/load_path_cache/path_scanner.rb +14 -3
- data/lib/bootsnap/load_path_cache/store.rb +16 -9
- data/lib/bootsnap/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5f10210480d5f0c9574fe970766d9ef4799e9a8a212f6ccafab6a61c2189481
|
4
|
+
data.tar.gz: 3502a4a6f2ab2614f470d1aaa4d648ec86ab0aebe9390074a71fc1b7544a9d1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53975108838cdfe27d2b8c9e7b0ef1a25100e85ad691063d2dfd35e6db600bf5c76591aeaf51117651fab7c96779c6877a86984bfa97eb7152afecbd42d77828
|
7
|
+
data.tar.gz: 294d0cf74421f374dfde4bc551cdcb3a4f6dd4a971c0d50f3f03eb59c73ae75554689077af0cdc85aa7765aa8944e8e3edd919380fcfea9742bf7391d54756a8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.7.4
|
4
|
+
|
5
|
+
* Stop raising errors when encoutering various file system errors. The cache is now best effort,
|
6
|
+
if somehow it can't be saved, bootsnapp will gracefully fallback to the original operation (e.g. `Kernel.require`).
|
7
|
+
(#353, #177, #262)
|
8
|
+
|
9
|
+
# 1.7.3
|
10
|
+
|
11
|
+
* Disable YAML precompilation when encountering YAML tags. (#351)
|
12
|
+
|
13
|
+
# 1.7.2
|
14
|
+
|
15
|
+
* Fix compatibility with msgpack < 1. (#349)
|
16
|
+
|
17
|
+
# 1.7.1
|
18
|
+
|
19
|
+
* Warn Ruby 2.5 users if they turn ISeq caching on. (#327, #244)
|
20
|
+
* Disable ISeq caching for the whole 2.5.x series again.
|
21
|
+
* Better handle hashing of Ruby strings. (#318)
|
22
|
+
|
3
23
|
# 1.7.0
|
4
24
|
|
5
25
|
* Fix detection of YAML files in gems.
|
data/ext/bootsnap/bootsnap.c
CHANGED
@@ -105,8 +105,7 @@ static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handl
|
|
105
105
|
static VALUE bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
|
106
106
|
|
107
107
|
/* Helpers */
|
108
|
-
static
|
109
|
-
static void bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
|
108
|
+
static void bs_cache_path(const char * cachedir, const VALUE path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
|
110
109
|
static int bs_read_key(int fd, struct bs_cache_key * key);
|
111
110
|
static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
|
112
111
|
static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
|
@@ -211,7 +210,7 @@ bs_compile_option_crc32_set(VALUE self, VALUE crc32_v)
|
|
211
210
|
* - 32 bits doesn't feel collision-resistant enough; 64 is nice.
|
212
211
|
*/
|
213
212
|
static uint64_t
|
214
|
-
|
213
|
+
fnv1a_64_iter_cstr(uint64_t h, const char *str)
|
215
214
|
{
|
216
215
|
unsigned char *s = (unsigned char *)str;
|
217
216
|
|
@@ -224,7 +223,21 @@ fnv1a_64_iter(uint64_t h, const char *str)
|
|
224
223
|
}
|
225
224
|
|
226
225
|
static uint64_t
|
227
|
-
|
226
|
+
fnv1a_64_iter(uint64_t h, const VALUE str)
|
227
|
+
{
|
228
|
+
unsigned char *s = (unsigned char *)RSTRING_PTR(str);
|
229
|
+
unsigned char *str_end = (unsigned char *)RSTRING_PTR(str) + RSTRING_LEN(str);
|
230
|
+
|
231
|
+
while (s < str_end) {
|
232
|
+
h ^= (uint64_t)*s++;
|
233
|
+
h += (h << 1) + (h << 4) + (h << 5) + (h << 7) + (h << 8) + (h << 40);
|
234
|
+
}
|
235
|
+
|
236
|
+
return h;
|
237
|
+
}
|
238
|
+
|
239
|
+
static uint64_t
|
240
|
+
fnv1a_64(const VALUE str)
|
228
241
|
{
|
229
242
|
uint64_t h = (uint64_t)0xcbf29ce484222325ULL;
|
230
243
|
return fnv1a_64_iter(h, str);
|
@@ -245,7 +258,7 @@ get_ruby_revision(void)
|
|
245
258
|
} else {
|
246
259
|
uint64_t hash;
|
247
260
|
|
248
|
-
hash = fnv1a_64(
|
261
|
+
hash = fnv1a_64(ruby_revision);
|
249
262
|
return (uint32_t)(hash >> 32);
|
250
263
|
}
|
251
264
|
}
|
@@ -265,19 +278,19 @@ get_ruby_platform(void)
|
|
265
278
|
VALUE ruby_platform;
|
266
279
|
|
267
280
|
ruby_platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
|
268
|
-
hash = fnv1a_64(
|
281
|
+
hash = fnv1a_64(ruby_platform);
|
269
282
|
|
270
283
|
#ifdef _WIN32
|
271
284
|
return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
|
272
285
|
#elif defined(__GLIBC__)
|
273
|
-
hash =
|
286
|
+
hash = fnv1a_64_iter_cstr(hash, gnu_get_libc_version());
|
274
287
|
return (uint32_t)(hash >> 32);
|
275
288
|
#else
|
276
289
|
struct utsname utsname;
|
277
290
|
|
278
291
|
/* Not worth crashing if this fails; lose extra cache invalidation potential */
|
279
292
|
if (uname(&utsname) >= 0) {
|
280
|
-
hash =
|
293
|
+
hash = fnv1a_64_iter_cstr(hash, utsname.version);
|
281
294
|
}
|
282
295
|
|
283
296
|
return (uint32_t)(hash >> 32);
|
@@ -292,13 +305,13 @@ get_ruby_platform(void)
|
|
292
305
|
* The path will look something like: <cachedir>/12/34567890abcdef
|
293
306
|
*/
|
294
307
|
static void
|
295
|
-
bs_cache_path(const char * cachedir, const
|
308
|
+
bs_cache_path(const char * cachedir, const VALUE path, char (* cache_path)[MAX_CACHEPATH_SIZE])
|
296
309
|
{
|
297
310
|
uint64_t hash = fnv1a_64(path);
|
298
311
|
uint8_t first_byte = (hash >> (64 - 8));
|
299
312
|
uint64_t remainder = hash & 0x00ffffffffffffff;
|
300
313
|
|
301
|
-
sprintf(*cache_path, "%s/%
|
314
|
+
sprintf(*cache_path, "%s/%02"PRIx8"/%014"PRIx64, cachedir, first_byte, remainder);
|
302
315
|
}
|
303
316
|
|
304
317
|
/*
|
@@ -344,7 +357,7 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE arg
|
|
344
357
|
char cache_path[MAX_CACHEPATH_SIZE];
|
345
358
|
|
346
359
|
/* generate cache path to cache_path */
|
347
|
-
bs_cache_path(cachedir,
|
360
|
+
bs_cache_path(cachedir, path_v, &cache_path);
|
348
361
|
|
349
362
|
return bs_fetch(path, path_v, cache_path, handler, args);
|
350
363
|
}
|
@@ -371,7 +384,7 @@ bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
|
|
371
384
|
char cache_path[MAX_CACHEPATH_SIZE];
|
372
385
|
|
373
386
|
/* generate cache path to cache_path */
|
374
|
-
bs_cache_path(cachedir,
|
387
|
+
bs_cache_path(cachedir, path_v, &cache_path);
|
375
388
|
|
376
389
|
return bs_precompile(path, path_v, cache_path, handler);
|
377
390
|
}
|
@@ -451,8 +464,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
|
|
451
464
|
fd = open(path, O_RDONLY);
|
452
465
|
if (fd < 0) {
|
453
466
|
*errno_provenance = "bs_fetch:open_cache_file:open";
|
454
|
-
|
455
|
-
return ERROR_WITH_ERRNO;
|
467
|
+
return CACHE_MISS;
|
456
468
|
}
|
457
469
|
#ifdef _WIN32
|
458
470
|
setmode(fd, O_BINARY);
|
@@ -750,9 +762,11 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
|
|
750
762
|
/* If storage_data isn't a string, we can't cache it */
|
751
763
|
if (!RB_TYPE_P(storage_data, T_STRING)) goto invalid_type_storage_data;
|
752
764
|
|
753
|
-
/*
|
754
|
-
|
755
|
-
|
765
|
+
/* Attempt to write the cache key and storage_data to the cache directory.
|
766
|
+
* We do however ignore any failures to persist the cache, as it's better
|
767
|
+
* to move along, than to interrupt the process.
|
768
|
+
*/
|
769
|
+
atomic_write_cache_file(cache_path, ¤t_key, storage_data, &errno_provenance);
|
756
770
|
|
757
771
|
/* Having written the cache, now convert storage_data to output_data */
|
758
772
|
exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
|
data/ext/bootsnap/extconf.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require("mkmf")
|
3
|
-
$CFLAGS << ' -O3 '
|
4
|
-
$CFLAGS << ' -std=c99'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
$CFLAGS << ' -Wall'
|
10
|
-
$CFLAGS << ' -Werror'
|
11
|
-
$CFLAGS << ' -Wextra'
|
12
|
-
$CFLAGS << ' -Wpedantic'
|
4
|
+
if RUBY_ENGINE == 'ruby'
|
5
|
+
$CFLAGS << ' -O3 '
|
6
|
+
$CFLAGS << ' -std=c99'
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
# ruby.h has some -Wpedantic fails in some cases
|
9
|
+
# (e.g. https://github.com/Shopify/bootsnap/issues/15)
|
10
|
+
unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
|
11
|
+
$CFLAGS << ' -Wall'
|
12
|
+
$CFLAGS << ' -Werror'
|
13
|
+
$CFLAGS << ' -Wextra'
|
14
|
+
$CFLAGS << ' -Wpedantic'
|
15
|
+
|
16
|
+
$CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
|
17
|
+
$CFLAGS << ' -Wno-keyword-macro' # hiding return
|
18
|
+
$CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
|
19
|
+
end
|
18
20
|
|
19
|
-
create_makefile("bootsnap/bootsnap")
|
21
|
+
create_makefile("bootsnap/bootsnap")
|
22
|
+
else
|
23
|
+
File.write("Makefile", dummy_makefile($srcdir).join(""))
|
24
|
+
end
|
data/lib/bootsnap.rb
CHANGED
@@ -54,6 +54,11 @@ module Bootsnap
|
|
54
54
|
"If you use Ruby 2.5 or newer this option is useless, if not upgrading is recommended."
|
55
55
|
end
|
56
56
|
|
57
|
+
if compile_cache_iseq && !iseq_cache_supported?
|
58
|
+
warn "Ruby 2.5 has a bug that break code tracing when code is loaded from cache. It is recommened " \
|
59
|
+
"to turn `compile_cache_iseq` off on Ruby 2.5"
|
60
|
+
end
|
61
|
+
|
57
62
|
Bootsnap::LoadPathCache.setup(
|
58
63
|
cache_path: cache_dir + '/bootsnap/load-path-cache',
|
59
64
|
development_mode: development_mode,
|
@@ -66,6 +71,13 @@ module Bootsnap
|
|
66
71
|
)
|
67
72
|
end
|
68
73
|
|
74
|
+
def self.iseq_cache_supported?
|
75
|
+
return @iseq_cache_supported if defined? @iseq_cache_supported
|
76
|
+
|
77
|
+
ruby_version = Gem::Version.new(RUBY_VERSION)
|
78
|
+
@iseq_cache_supported = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.6.0')
|
79
|
+
end
|
80
|
+
|
69
81
|
def self.default_setup
|
70
82
|
env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
|
71
83
|
development_mode = ['', nil, 'development'].include?(env)
|
@@ -92,14 +104,12 @@ module Bootsnap
|
|
92
104
|
cache_dir = File.join(app_root, 'tmp', 'cache')
|
93
105
|
end
|
94
106
|
|
95
|
-
ruby_version = Gem::Version.new(RUBY_VERSION)
|
96
|
-
iseq_cache_enabled = ruby_version < Gem::Version.new('2.5.0') || ruby_version >= Gem::Version.new('2.5.4')
|
97
107
|
|
98
108
|
setup(
|
99
109
|
cache_dir: cache_dir,
|
100
110
|
development_mode: development_mode,
|
101
111
|
load_path_cache: !ENV['DISABLE_BOOTSNAP_LOAD_PATH_CACHE'],
|
102
|
-
compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] &&
|
112
|
+
compile_cache_iseq: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'] && iseq_cache_supported?,
|
103
113
|
compile_cache_yaml: !ENV['DISABLE_BOOTSNAP_COMPILE_CACHE'],
|
104
114
|
)
|
105
115
|
|
@@ -8,8 +8,7 @@ module Bootsnap
|
|
8
8
|
attr_accessor(:msgpack_factory, :cache_dir, :supported_options)
|
9
9
|
|
10
10
|
def input_to_storage(contents, _)
|
11
|
-
|
12
|
-
obj = ::YAML.load(contents)
|
11
|
+
obj = strict_load(contents)
|
13
12
|
msgpack_factory.dump(obj)
|
14
13
|
rescue NoMethodError, RangeError
|
15
14
|
# The object included things that we can't serialize
|
@@ -27,6 +26,13 @@ module Bootsnap
|
|
27
26
|
::YAML.load(data, **(kwargs || {}))
|
28
27
|
end
|
29
28
|
|
29
|
+
def strict_load(payload, *args)
|
30
|
+
ast = ::YAML.parse(payload)
|
31
|
+
return ast unless ast
|
32
|
+
strict_visitor.create(*args).visit(ast)
|
33
|
+
end
|
34
|
+
ruby2_keywords :strict_load if respond_to?(:ruby2_keywords, true)
|
35
|
+
|
30
36
|
def precompile(path, cache_dir: YAML.cache_dir)
|
31
37
|
Bootsnap::CompileCache::Native.precompile(
|
32
38
|
cache_dir,
|
@@ -51,22 +57,25 @@ module Bootsnap
|
|
51
57
|
# see: https://github.com/msgpack/msgpack-ruby/pull/122
|
52
58
|
factory = MessagePack::Factory.new
|
53
59
|
factory.register_type(0x00, Symbol)
|
54
|
-
factory.register_type(
|
55
|
-
MessagePack::Timestamp::TYPE, # or just -1
|
56
|
-
Time,
|
57
|
-
packer: MessagePack::Time::Packer,
|
58
|
-
unpacker: MessagePack::Time::Unpacker
|
59
|
-
)
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
61
|
+
if defined? MessagePack::Timestamp
|
62
|
+
factory.register_type(
|
63
|
+
MessagePack::Timestamp::TYPE, # or just -1
|
64
|
+
Time,
|
65
|
+
packer: MessagePack::Time::Packer,
|
66
|
+
unpacker: MessagePack::Time::Unpacker
|
67
|
+
)
|
68
|
+
|
69
|
+
marshal_fallback = {
|
70
|
+
packer: ->(value) { Marshal.dump(value) },
|
71
|
+
unpacker: ->(payload) { Marshal.load(payload) },
|
72
|
+
}
|
73
|
+
{
|
74
|
+
Date => 0x01,
|
75
|
+
Regexp => 0x02,
|
76
|
+
}.each do |type, code|
|
77
|
+
factory.register_type(code, type, marshal_fallback)
|
78
|
+
end
|
70
79
|
end
|
71
80
|
|
72
81
|
self.msgpack_factory = factory
|
@@ -83,6 +92,17 @@ module Bootsnap
|
|
83
92
|
end
|
84
93
|
self.supported_options.freeze
|
85
94
|
end
|
95
|
+
|
96
|
+
def strict_visitor
|
97
|
+
self::NoTagsVisitor ||= Class.new(Psych::Visitors::ToRuby) do
|
98
|
+
def visit(target)
|
99
|
+
if target.tag
|
100
|
+
raise Uncompilable, "YAML tags are not supported: #{target.tag}"
|
101
|
+
end
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
86
106
|
end
|
87
107
|
|
88
108
|
module Patch
|
@@ -10,8 +10,8 @@ module Bootsnap
|
|
10
10
|
def initialize(store, path_obj, development_mode: false)
|
11
11
|
@development_mode = development_mode
|
12
12
|
@store = store
|
13
|
-
@mutex =
|
14
|
-
@path_obj = path_obj.map! { |f| File.exist?(f) ? File.realpath(f) : f }
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@path_obj = path_obj.map! { |f| PathScanner.os_path(File.exist?(f) ? File.realpath(f) : f.dup) }
|
15
15
|
@has_relative_paths = nil
|
16
16
|
reinitialize
|
17
17
|
end
|
@@ -178,25 +178,42 @@ module Bootsnap
|
|
178
178
|
|
179
179
|
if DLEXT2
|
180
180
|
def search_index(f)
|
181
|
-
try_index(
|
181
|
+
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f + DLEXT2) || try_index(f)
|
182
182
|
end
|
183
183
|
|
184
184
|
def maybe_append_extension(f)
|
185
|
-
try_ext(
|
185
|
+
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || try_ext(f + DLEXT2) || f
|
186
186
|
end
|
187
187
|
else
|
188
188
|
def search_index(f)
|
189
|
-
try_index(
|
189
|
+
try_index(f + DOT_RB) || try_index(f + DLEXT) || try_index(f)
|
190
190
|
end
|
191
191
|
|
192
192
|
def maybe_append_extension(f)
|
193
|
-
try_ext(
|
193
|
+
try_ext(f + DOT_RB) || try_ext(f + DLEXT) || f
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
-
|
198
|
-
|
199
|
-
|
197
|
+
s = rand.to_s.force_encoding(Encoding::US_ASCII).freeze
|
198
|
+
if s.respond_to?(:-@)
|
199
|
+
if (-s).equal?(s) && (-s.dup).equal?(s)
|
200
|
+
def try_index(f)
|
201
|
+
if (p = @index[f])
|
202
|
+
-(File.join(p, f).freeze)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
def try_index(f)
|
207
|
+
if (p = @index[f])
|
208
|
+
-File.join(p, f).untaint
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
else
|
213
|
+
def try_index(f)
|
214
|
+
if (p = @index[f])
|
215
|
+
File.join(p, f)
|
216
|
+
end
|
200
217
|
end
|
201
218
|
end
|
202
219
|
|
@@ -26,7 +26,7 @@ module Bootsnap
|
|
26
26
|
class LoadedFeaturesIndex
|
27
27
|
def initialize
|
28
28
|
@lfi = {}
|
29
|
-
@mutex =
|
29
|
+
@mutex = Mutex.new
|
30
30
|
|
31
31
|
# In theory the user could mutate $LOADED_FEATURES and invalidate our
|
32
32
|
# cache. If this ever comes up in practice — or if you, the
|
@@ -33,10 +33,10 @@ module Bootsnap
|
|
33
33
|
requirables = []
|
34
34
|
walk(path, nil) do |relative_path, absolute_path, is_directory|
|
35
35
|
if is_directory
|
36
|
-
dirs << relative_path
|
36
|
+
dirs << os_path(relative_path)
|
37
37
|
!contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
|
38
38
|
elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
|
39
|
-
requirables << relative_path
|
39
|
+
requirables << os_path(relative_path)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
[requirables, dirs]
|
@@ -45,7 +45,7 @@ module Bootsnap
|
|
45
45
|
def walk(absolute_dir_path, relative_dir_path, &block)
|
46
46
|
Dir.foreach(absolute_dir_path) do |name|
|
47
47
|
next if name.start_with?('.')
|
48
|
-
relative_path = relative_dir_path ?
|
48
|
+
relative_path = relative_dir_path ? File.join(relative_dir_path, name) : name
|
49
49
|
|
50
50
|
absolute_path = "#{absolute_dir_path}/#{name}"
|
51
51
|
if File.directory?(absolute_path)
|
@@ -57,6 +57,17 @@ module Bootsnap
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
if RUBY_VERSION >= '3.1'
|
62
|
+
def os_path(path)
|
63
|
+
path.freeze
|
64
|
+
end
|
65
|
+
else
|
66
|
+
def os_path(path)
|
67
|
+
path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
|
68
|
+
path.freeze
|
69
|
+
end
|
70
|
+
end
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -12,8 +12,7 @@ module Bootsnap
|
|
12
12
|
|
13
13
|
def initialize(store_path)
|
14
14
|
@store_path = store_path
|
15
|
-
|
16
|
-
@txn_mutex = defined?(::Mutex) ? ::Mutex.new : ::Thread::Mutex.new
|
15
|
+
@txn_mutex = Mutex.new
|
17
16
|
@dirty = false
|
18
17
|
load_data
|
19
18
|
end
|
@@ -63,12 +62,18 @@ module Bootsnap
|
|
63
62
|
|
64
63
|
def load_data
|
65
64
|
@data = begin
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
File.open(@store_path, encoding: Encoding::BINARY) do |io|
|
66
|
+
MessagePack.load(io)
|
67
|
+
end
|
68
|
+
# handle malformed data due to upgrade incompatibility
|
69
|
+
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
70
|
+
{}
|
71
|
+
rescue ArgumentError => error
|
72
|
+
if error.message =~ /negative array size/
|
73
|
+
{}
|
74
|
+
else
|
75
|
+
raise
|
76
|
+
end
|
72
77
|
end
|
73
78
|
end
|
74
79
|
|
@@ -80,7 +85,9 @@ module Bootsnap
|
|
80
85
|
exclusive_write = File::Constants::CREAT | File::Constants::EXCL | File::Constants::WRONLY
|
81
86
|
# `encoding:` looks redundant wrt `binwrite`, but necessary on windows
|
82
87
|
# because binary is part of mode.
|
83
|
-
File.
|
88
|
+
File.open(tmp, mode: exclusive_write, encoding: Encoding::BINARY) do |io|
|
89
|
+
MessagePack.dump(@data, io, freeze: true)
|
90
|
+
end
|
84
91
|
FileUtils.mv(tmp, @store_path)
|
85
92
|
rescue Errno::EEXIST
|
86
93
|
retry
|
data/lib/bootsnap/version.rb
CHANGED
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.7.
|
4
|
+
version: 1.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|