bootsnap 1.1.5-java → 1.1.6-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
2
  SHA1:
3
- metadata.gz: 5c55ecdb3943b7b5a7ab1c2f73ac8528b7a46b1c
4
- data.tar.gz: 885adb923706243471045e91d52e4366e1fa2801
3
+ metadata.gz: 83d81136127e353b9707007de28cda32978abfab
4
+ data.tar.gz: ccfa356d26674743a55c1dbcd797356363dc2927
5
5
  SHA512:
6
- metadata.gz: e13085180028c2af5c050f9d2a94e063e4272fdc73a249ccc5d9a1e258d86381e982df664d079f8fbbbf4fec62f911d635387d2c89da22d93d1d501891e263b8
7
- data.tar.gz: 181185f4aa8458f864bf61cf03d194553c66c8c0412e9e828caa3560709b289ff9ed6a9b3ce5199e1d6b55d38eae31f0f3407a721378b45d3a7141fb51a83d9d
6
+ metadata.gz: 7e288dbca937cf5486423fb21857a7a23d9f0788af5879134dbc01ff469ba01781cef7da3711937412f997ca83a5e5b5ff3c7ab819c4bf25fdbf2df75e8ca8d6
7
+ data.tar.gz: 5a53523989729d26dc67eb579e2fef3f21f4f3da427b6cb982452ba090aee7c608bdcbb6fe13514d22e003cd66341786c8eee5fa3bac5723b378a69338af8f9f
@@ -1,5 +1,4 @@
1
- os: osx
2
1
  language: ruby
3
- rvm: ruby-2.4.0
2
+ rvm: ruby-2.4.1
4
3
  before_script: rake
5
4
  script: bin/testunit
@@ -1,3 +1,7 @@
1
+ # 1.1.6
2
+
3
+ * Assortment of minor bugfixes
4
+
1
5
  # 1.1.5
2
6
 
3
7
  * bugfix re-release of 1.1.4
data/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # Bootsnap [![Build Status](https://travis-ci.org/Shopify/bootsnap.svg?branch=master)](https://travis-ci.org/Shopify/bootsnap)
2
2
 
3
- **Beta-quality. See [the last section of this README](#trustworthiness).**
4
-
5
3
  Bootsnap is a library that plugs into Ruby, with optional support for `ActiveSupport` and `YAML`,
6
4
  to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
7
5
 
@@ -48,6 +46,11 @@ Bootsnap.setup(
48
46
  'bootsnap')` using [this trick](https://github.com/Shopify/bootsnap/wiki/Bootlib::Require). This
49
47
  will help optimize boot time further if you have an extremely large `$LOAD_PATH`.
50
48
 
49
+ Note: Bootsnap and [Spring](https://github.com/rails/spring) are orthogonal tools. While Bootsnap
50
+ speeds up the loading of individual source files, Spring keeps a copy of a pre-booted Rails process
51
+ on hand to completely skip parts of the boot process the next time it's needed. The two tools work
52
+ well together, and are both included in a newly-generated Rails applications by default.
53
+
51
54
  ## How does this work?
52
55
 
53
56
  Bootsnap optimizes methods to cache results of expensive computations, and can be grouped
@@ -264,21 +267,3 @@ open /c/nope.bundle -> -1
264
267
  ```
265
268
  # (nothing!)
266
269
  ```
267
-
268
- ## Trustworthiness
269
-
270
- We use the `*_path_cache` features in production and haven't experienced any issues in a long time.
271
-
272
- The `compile_cache_*` features work well for us in development on macOS. It should work on Linux,
273
- and we intend to deploy it in production, but we haven't yet.
274
-
275
- `disable_trace` should be completely safe, but we don't really use it because some people like to
276
- use tools that make use of `trace` instructions.
277
-
278
- | feature | where we're using it |
279
- |-|-|
280
- | `load_path_cache` | everywhere |
281
- | `autoload_path_cache` | everywhere |
282
- | `disable_trace` | nowhere, but it's safe unless you need tracing |
283
- | `compile_cache_iseq` | development, but probably safe to use everywhere |
284
- | `compile_cache_yaml` | development, but probably safe to use everywhere |
data/dev.yml CHANGED
@@ -5,5 +5,6 @@ up:
5
5
  - ruby: 2.3.3
6
6
  - bundler
7
7
  commands:
8
+ build: rake compile
8
9
  test: 'rake compile && exec bin/testunit'
9
10
  style: 'exec rubocop -D'
@@ -32,7 +32,7 @@
32
32
  /*
33
33
  * An instance of this key is written as the first 64 bytes of each cache file.
34
34
  * The mtime and size members track whether the file contents have changed, and
35
- * the version, os_version, compile_option, and ruby_revision members track
35
+ * the version, ruby_platform, compile_option, and ruby_revision members track
36
36
  * changes to the environment that could invalidate compile results without
37
37
  * file contents having changed. The data_size member is not truly part of the
38
38
  * "key". Really, this could be called a "header" with the first six members
@@ -45,7 +45,7 @@
45
45
  */
46
46
  struct bs_cache_key {
47
47
  uint32_t version;
48
- uint32_t os_version;
48
+ uint32_t ruby_platform;
49
49
  uint32_t compile_option;
50
50
  uint32_t ruby_revision;
51
51
  uint64_t size;
@@ -67,9 +67,9 @@ STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
67
67
  /* Effectively a schema version. Bumping invalidates all previous caches */
68
68
  static const uint32_t current_version = 2;
69
69
 
70
- /* Derived from kernel or libc version; intended to roughly correspond to when
71
- * ABIs have changed, requiring recompilation of native gems. */
72
- static uint32_t current_os_version;
70
+ /* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
71
+ * new OS ABI, etc. */
72
+ static uint32_t current_ruby_platform;
73
73
  /* Invalidates cache when switching ruby versions */
74
74
  static uint32_t current_ruby_revision;
75
75
  /* Invalidates cache when RubyVM::InstructionSequence.compile_option changes */
@@ -92,10 +92,10 @@ static void bs_cache_path(const char * cachedir, const char * path, char ** cach
92
92
  static int bs_read_key(int fd, struct bs_cache_key * key);
93
93
  static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
94
94
  static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
95
- static int open_current_file(char * path, struct bs_cache_key * key);
96
- static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag);
95
+ static int open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance);
96
+ static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance);
97
97
  static VALUE prot_exception_for_errno(VALUE err);
98
- static uint32_t get_os_version(void);
98
+ static uint32_t get_ruby_platform(void);
99
99
 
100
100
  /*
101
101
  * Helper functions to call ruby methods on handler object without crashing on
@@ -136,7 +136,7 @@ Init_bootsnap(void)
136
136
  rb_eBootsnap_CompileCache_Uncompilable = rb_define_class_under(rb_mBootsnap_CompileCache, "Uncompilable", rb_eStandardError);
137
137
 
138
138
  current_ruby_revision = FIX2INT(rb_const_get(rb_cObject, rb_intern("RUBY_REVISION")));
139
- current_os_version = get_os_version();
139
+ current_ruby_platform = get_ruby_platform();
140
140
 
141
141
  uncompilable = rb_intern("__bootsnap_uncompilable__");
142
142
 
@@ -173,10 +173,9 @@ bs_compile_option_crc32_set(VALUE self, VALUE crc32_v)
173
173
  * - 32 bits doesn't feel collision-resistant enough; 64 is nice.
174
174
  */
175
175
  static uint64_t
176
- fnv1a_64(const char *str)
176
+ fnv1a_64_iter(uint64_t h, const char *str)
177
177
  {
178
178
  unsigned char *s = (unsigned char *)str;
179
- uint64_t h = (uint64_t)0xcbf29ce484222325ULL;
180
179
 
181
180
  while (*s) {
182
181
  h ^= (uint64_t)*s++;
@@ -186,26 +185,42 @@ fnv1a_64(const char *str)
186
185
  return h;
187
186
  }
188
187
 
188
+ static uint64_t
189
+ fnv1a_64(const char *str)
190
+ {
191
+ uint64_t h = (uint64_t)0xcbf29ce484222325ULL;
192
+ return fnv1a_64_iter(h, str);
193
+ }
194
+
189
195
  /*
190
- * The idea here is that we want a cache key member that changes when the OS
191
- * changes in such a way as to make existing compiled ISeqs unloadable.
196
+ * When ruby's version doesn't change, but it's recompiled on a different OS
197
+ * (or OS version), we need to invalidate the cache.
198
+ *
199
+ * We actually factor in some extra information here, to be extra confident
200
+ * that we don't try to re-use caches that will not be compatible, by factoring
201
+ * in utsname.version.
192
202
  */
193
203
  static uint32_t
194
- get_os_version(void)
204
+ get_ruby_platform(void)
195
205
  {
196
- #ifdef _WIN32
197
- return (uint32_t)GetVersion();
198
- #else
199
206
  uint64_t hash;
200
- struct utsname utsname;
207
+ VALUE ruby_platform;
201
208
 
202
- /* Not worth crashing if this fails; lose cache invalidation potential */
203
- if (uname(&utsname) < 0) return 0;
209
+ ruby_platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
210
+ hash = fnv1a_64(RSTRING_PTR(ruby_platform));
204
211
 
205
- hash = fnv1a_64(utsname.version);
212
+ #ifdef _WIN32
213
+ return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
214
+ #else
215
+ struct utsname utsname;
216
+
217
+ /* Not worth crashing if this fails; lose extra cache invalidation potential */
218
+ if (uname(&utsname) >= 0) {
219
+ hash = fnv1a_64_iter(hash, utsname.version);
220
+ }
206
221
 
207
222
  return (uint32_t)(hash >> 32);
208
- #endif
223
+ #endif
209
224
  }
210
225
 
211
226
  /*
@@ -239,7 +254,7 @@ cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2)
239
254
  {
240
255
  return (
241
256
  k1->version == k2->version &&
242
- k1->os_version == k2->os_version &&
257
+ k1->ruby_platform == k2->ruby_platform &&
243
258
  k1->compile_option == k2->compile_option &&
244
259
  k1->ruby_revision == k2->ruby_revision &&
245
260
  k1->size == k2->size &&
@@ -279,24 +294,28 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
279
294
  * was loaded.
280
295
  */
281
296
  static int
282
- open_current_file(char * path, struct bs_cache_key * key)
297
+ open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance)
283
298
  {
284
299
  struct stat statbuf;
285
300
  int fd;
286
301
 
287
302
  fd = open(path, O_RDONLY);
288
- if (fd < 0) return fd;
303
+ if (fd < 0) {
304
+ *errno_provenance = (char *)"bs_fetch:open_current_file:open";
305
+ return fd;
306
+ }
289
307
  #ifdef _WIN32
290
308
  setmode(fd, O_BINARY);
291
309
  #endif
292
310
 
293
311
  if (fstat(fd, &statbuf) < 0) {
312
+ *errno_provenance = (char *)"bs_fetch:open_current_file:fstat";
294
313
  close(fd);
295
314
  return -1;
296
315
  }
297
316
 
298
317
  key->version = current_version;
299
- key->os_version = current_os_version;
318
+ key->ruby_platform = current_ruby_platform;
300
319
  key->compile_option = current_compile_option_crc32;
301
320
  key->ruby_revision = current_ruby_revision;
302
321
  key->size = (uint64_t)statbuf.st_size;
@@ -336,12 +355,13 @@ bs_read_key(int fd, struct bs_cache_key * key)
336
355
  * - ERROR_WITH_ERRNO (-1, errno is set)
337
356
  */
338
357
  static int
339
- open_cache_file(const char * path, struct bs_cache_key * key)
358
+ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_provenance)
340
359
  {
341
360
  int fd, res;
342
361
 
343
362
  fd = open(path, O_RDONLY);
344
363
  if (fd < 0) {
364
+ *errno_provenance = (char *)"bs_fetch:open_cache_file:open";
345
365
  if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
346
366
  return ERROR_WITH_ERRNO;
347
367
  }
@@ -351,6 +371,7 @@ open_cache_file(const char * path, struct bs_cache_key * key)
351
371
 
352
372
  res = bs_read_key(fd, key);
353
373
  if (res < 0) {
374
+ *errno_provenance = (char *)"bs_fetch:open_cache_file:read";
354
375
  close(fd);
355
376
  return res;
356
377
  }
@@ -374,7 +395,7 @@ open_cache_file(const char * path, struct bs_cache_key * key)
374
395
  * or exception, will be the final data returnable to the user.
375
396
  */
376
397
  static int
377
- fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag)
398
+ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance)
378
399
  {
379
400
  char * data = NULL;
380
401
  ssize_t nread;
@@ -383,6 +404,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
383
404
  VALUE storage_data;
384
405
 
385
406
  if (data_size > 100000000000) {
407
+ *errno_provenance = (char *)"bs_fetch:fetch_cached_data:datasize";
386
408
  errno = EINVAL; /* because wtf? */
387
409
  ret = -1;
388
410
  goto done;
@@ -390,6 +412,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
390
412
  data = ALLOC_N(char, data_size);
391
413
  nread = read(fd, data, data_size);
392
414
  if (nread < 0) {
415
+ *errno_provenance = (char *)"bs_fetch:fetch_cached_data:read";
393
416
  ret = -1;
394
417
  goto done;
395
418
  }
@@ -441,12 +464,12 @@ mkpath(char * file_path, mode_t mode)
441
464
  * path.
442
465
  */
443
466
  static int
444
- atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data)
467
+ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
445
468
  {
446
469
  char template[MAX_CACHEPATH_SIZE + 20];
447
470
  char * dest;
448
471
  char * tmp_path;
449
- int fd;
472
+ int fd, ret;
450
473
  ssize_t nwrite;
451
474
 
452
475
  dest = strncpy(template, path, MAX_CACHEPATH_SIZE);
@@ -455,9 +478,15 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data)
455
478
  tmp_path = mktemp(template);
456
479
  fd = open(tmp_path, O_WRONLY | O_CREAT, 0644);
457
480
  if (fd < 0) {
458
- if (mkpath(path, 0755) < 0) return -1;
481
+ if (mkpath(path, 0755) < 0) {
482
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
483
+ return -1;
484
+ }
459
485
  fd = open(tmp_path, O_WRONLY | O_CREAT, 0644);
460
- if (fd < 0) return -1;
486
+ if (fd < 0) {
487
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:open";
488
+ return -1;
489
+ }
461
490
  }
462
491
  #ifdef _WIN32
463
492
  setmode(fd, O_BINARY);
@@ -465,8 +494,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data)
465
494
 
466
495
  key->data_size = RSTRING_LEN(data);
467
496
  nwrite = write(fd, key, KEY_SIZE);
468
- if (nwrite < 0) return -1;
497
+ if (nwrite < 0) {
498
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:write";
499
+ return -1;
500
+ }
469
501
  if (nwrite != KEY_SIZE) {
502
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:keysize";
470
503
  errno = EIO; /* Lies but whatever */
471
504
  return -1;
472
505
  }
@@ -474,12 +507,17 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data)
474
507
  nwrite = write(fd, RSTRING_PTR(data), RSTRING_LEN(data));
475
508
  if (nwrite < 0) return -1;
476
509
  if (nwrite != RSTRING_LEN(data)) {
510
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:writelength";
477
511
  errno = EIO; /* Lies but whatever */
478
512
  return -1;
479
513
  }
480
514
 
481
515
  close(fd);
482
- return rename(tmp_path, path);
516
+ ret = rename(tmp_path, path);
517
+ if (ret < 0) {
518
+ *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:rename";
519
+ }
520
+ return ret;
483
521
  }
484
522
 
485
523
  /*
@@ -502,10 +540,15 @@ prot_exception_for_errno(VALUE err)
502
540
  /* Read contents from an fd, whose contents are asserted to be +size+ bytes
503
541
  * long, into a buffer */
504
542
  static ssize_t
505
- bs_read_contents(int fd, size_t size, char ** contents)
543
+ bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance)
506
544
  {
545
+ ssize_t nread;
507
546
  *contents = ALLOC_N(char, size);
508
- return read(fd, *contents, size);
547
+ nread = read(fd, *contents, size);
548
+ if (nread < 0) {
549
+ *errno_provenance = (char *)"bs_fetch:bs_read_contents:read";
550
+ }
551
+ return nread;
509
552
  }
510
553
 
511
554
  /*
@@ -513,24 +556,24 @@ bs_read_contents(int fd, size_t size, char ** contents)
513
556
  * Bootsnap::CompileCache::Native.fetch.
514
557
  *
515
558
  * There are three "formats" in use here:
516
- * 1. "input" fomat, which is what we load from the source file;
559
+ * 1. "input" format, which is what we load from the source file;
517
560
  * 2. "storage" format, which we write to the cache;
518
561
  * 3. "output" format, which is what we return.
519
562
  *
520
563
  * E.g., For ISeq compilation:
521
- * input: ruby source, as text
564
+ * input: ruby source, as text
522
565
  * storage: binary string (RubyVM::InstructionSequence#to_binary)
523
- * output: Instance of RubyVM::InstructionSequence
566
+ * output: Instance of RubyVM::InstructionSequence
524
567
  *
525
568
  * And for YAML:
526
- * input: yaml as text
569
+ * input: yaml as text
527
570
  * storage: MessagePack or Marshal text
528
- * output: ruby object, loaded from yaml/messagepack/marshal
571
+ * output: ruby object, loaded from yaml/messagepack/marshal
529
572
  *
530
- * The handler passed in must support three messages:
531
- * * storage_to_output(s) -> o
532
- * * input_to_output(i) -> o
533
- * * input_to_storage(i) -> s
573
+ * A handler<I,S,O> passed in must support three messages:
574
+ * * storage_to_output(S) -> O
575
+ * * input_to_output(I) -> O
576
+ * * input_to_storage(I) -> S
534
577
  * (input_to_storage may raise Bootsnap::CompileCache::Uncompilable, which
535
578
  * will prevent caching and cause output to be generated with
536
579
  * input_to_output)
@@ -558,7 +601,8 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
558
601
  struct bs_cache_key cached_key, current_key;
559
602
  char * contents = NULL;
560
603
  int cache_fd = -1, current_fd = -1;
561
- int res, valid_cache, exception_tag = 0;
604
+ int res, valid_cache = 0, exception_tag = 0;
605
+ char * errno_provenance = NULL;
562
606
 
563
607
  VALUE input_data; /* data read from source file, e.g. YAML or ruby source */
564
608
  VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
@@ -567,20 +611,27 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
567
611
  VALUE exception; /* ruby exception object to raise instead of returning */
568
612
 
569
613
  /* Open the source file and generate a cache key for it */
570
- current_fd = open_current_file(path, &current_key);
614
+ current_fd = open_current_file(path, &current_key, &errno_provenance);
571
615
  if (current_fd < 0) goto fail_errno;
572
616
 
573
617
  /* Open the cache key if it exists, and read its cache key in */
574
- cache_fd = open_cache_file(cache_path, &cached_key);
575
- if (cache_fd < 0 && cache_fd != CACHE_MISSING_OR_INVALID) goto fail_errno;
576
-
577
- /* True if the cache existed and no invalidating changes have occurred since
578
- * it was generated. */
579
- valid_cache = cache_key_equal(&current_key, &cached_key);
618
+ cache_fd = open_cache_file(cache_path, &cached_key, &errno_provenance);
619
+ if (cache_fd == CACHE_MISSING_OR_INVALID) {
620
+ /* This is ok: valid_cache remains false, we re-populate it. */
621
+ } else if (cache_fd < 0) {
622
+ goto fail_errno;
623
+ } else {
624
+ /* True if the cache existed and no invalidating changes have occurred since
625
+ * it was generated. */
626
+ valid_cache = cache_key_equal(&current_key, &cached_key);
627
+ }
580
628
 
581
629
  if (valid_cache) {
582
630
  /* Fetch the cache data and return it if we're able to load it successfully */
583
- res = fetch_cached_data(cache_fd, (ssize_t)cached_key.data_size, handler, &output_data, &exception_tag);
631
+ res = fetch_cached_data(
632
+ cache_fd, (ssize_t)cached_key.data_size, handler,
633
+ &output_data, &exception_tag, &errno_provenance
634
+ );
584
635
  if (exception_tag != 0) goto raise;
585
636
  else if (res == CACHE_MISSING_OR_INVALID) valid_cache = 0;
586
637
  else if (res == ERROR_WITH_ERRNO) goto fail_errno;
@@ -591,7 +642,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
591
642
  /* Cache is stale, invalid, or missing. Regenerate and write it out. */
592
643
 
593
644
  /* Read the contents of the source file into a buffer */
594
- if (bs_read_contents(current_fd, current_key.size, &contents) < 0) goto fail_errno;
645
+ if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
595
646
  input_data = rb_str_new_static(contents, current_key.size);
596
647
 
597
648
  /* Try to compile the input_data using input_to_storage(input_data) */
@@ -608,7 +659,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
608
659
  if (!RB_TYPE_P(storage_data, T_STRING)) goto invalid_type_storage_data;
609
660
 
610
661
  /* Write the cache key and storage_data to the cache directory */
611
- res = atomic_write_cache_file(cache_path, &current_key, storage_data);
662
+ res = atomic_write_cache_file(cache_path, &current_key, storage_data, &errno_provenance);
612
663
  if (res < 0) goto fail_errno;
613
664
 
614
665
  /* Having written the cache, now convert storage_data to output_data */
@@ -618,7 +669,10 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
618
669
  /* If output_data is nil, delete the cache entry and generate the output
619
670
  * using input_to_output */
620
671
  if (NIL_P(output_data)) {
621
- if (unlink(cache_path) < 0) goto fail_errno;
672
+ if (unlink(cache_path) < 0) {
673
+ errno_provenance = (char *)"bs_fetch:unlink";
674
+ goto fail_errno;
675
+ }
622
676
  bs_input_to_output(handler, input_data, &output_data, &exception_tag);
623
677
  if (exception_tag != 0) goto raise;
624
678
  }
@@ -637,6 +691,9 @@ fail_errno:
637
691
  CLEANUP;
638
692
  exception = rb_protect(prot_exception_for_errno, INT2FIX(errno), &res);
639
693
  if (res) exception = rb_eStandardError;
694
+ if (errno_provenance != NULL) {
695
+ exception = rb_exc_new_str(exception, rb_str_new2(errno_provenance));
696
+ }
640
697
  rb_exc_raise(exception);
641
698
  __builtin_unreachable();
642
699
  raise:
@@ -655,7 +712,17 @@ invalid_type_storage_data:
655
712
  /********************* Handler Wrappers **************************************/
656
713
  /*****************************************************************************
657
714
  * Everything after this point in the file is just wrappers to deal with ruby's
658
- * clunky method of handling exceptions from ruby methods invoked from C.
715
+ * clunky method of handling exceptions from ruby methods invoked from C:
716
+ *
717
+ * In order to call a ruby method from C, while protecting against crashing in
718
+ * the event of an exception, we must call the method with rb_protect().
719
+ *
720
+ * rb_protect takes a C function and precisely one argument; however, we want
721
+ * to pass multiple arguments, so we must create structs to wrap them up.
722
+ *
723
+ * These functions return an exception_tag, which, if non-zero, indicates an
724
+ * exception that should be jumped to with rb_jump_tag after cleaning up
725
+ * allocated resources.
659
726
  */
660
727
 
661
728
  struct s2o_data {
@@ -1,4 +1,5 @@
1
1
  require_relative 'bootsnap/version'
2
+ require_relative 'bootsnap/bundler'
2
3
  require_relative 'bootsnap/load_path_cache'
3
4
  require_relative 'bootsnap/compile_cache'
4
5
 
@@ -0,0 +1,12 @@
1
+ module Bootsnap
2
+ module_function
3
+
4
+ def bundler?
5
+ # Bundler environment variable
6
+ ['BUNDLE_BIN_PATH', 'BUNDLE_GEMFILE'].each do |current|
7
+ return true if ENV.key?(current)
8
+ end
9
+
10
+ false
11
+ end
12
+ end
@@ -45,6 +45,10 @@ module Bootsnap
45
45
  # NoMethodError is a NameError, but we only want to handle actual
46
46
  # NameError instances.
47
47
  raise unless e.class == NameError
48
+ # We can only confidently handle cases when *this* constant fails
49
+ # to load, not other constants referred to by it.
50
+ raise unless e.name == const_name
51
+ # If the constant was actually loaded, something else went wrong?
48
52
  raise if from_mod.const_defined?(const_name)
49
53
  CoreExt::ActiveSupport.without_bootsnap_cache { super }
50
54
  end
@@ -99,7 +99,7 @@ module Bootsnap
99
99
  @stability ||= begin
100
100
  if Gem.path.detect { |p| expanded_path.start_with?(p.to_s) }
101
101
  STABLE
102
- elsif expanded_path.start_with?(Bundler.bundle_path.to_s)
102
+ elsif Bootsnap.bundler? && expanded_path.start_with?(Bundler.bundle_path.to_s)
103
103
  STABLE
104
104
  elsif expanded_path.start_with?(RUBY_LIBDIR) && !expanded_path.start_with?(RUBY_SITEDIR)
105
105
  STABLE
@@ -15,7 +15,8 @@ module Bootsnap
15
15
  REQUIRABLES_AND_DIRS = "/{,*/**/}*{#{DOT_RB},#{DL_EXTENSIONS.join(',')},/}"
16
16
  NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
17
17
  ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/
18
- BUNDLE_PATH = (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
18
+ BUNDLE_PATH = Bootsnap.bundler? ?
19
+ (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze : ''.freeze
19
20
 
20
21
  def self.call(path)
21
22
  path = path.to_s
@@ -69,7 +69,7 @@ module Bootsnap
69
69
  def dump_data
70
70
  # Change contents atomically so other processes can't get invalid
71
71
  # caches if they read at an inopportune time.
72
- tmp = "#{@store_path}.#{(rand * 100000).to_i}.tmp"
72
+ tmp = "#{@store_path}.#{Process.pid}.#{(rand * 100000).to_i}.tmp"
73
73
  FileUtils.mkpath(File.dirname(tmp))
74
74
  File.binwrite(tmp, MessagePack.dump(@data))
75
75
  FileUtils.mv(tmp, @store_path)
@@ -4,16 +4,10 @@ env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || ENV['ENV']
4
4
  development_mode = ['', nil, 'development'].include?(env)
5
5
 
6
6
  # only enable on 'ruby' (MRI), POSIX (darin, linux, *bsd), and >= 2.3.0
7
- enable_cc = \
8
- RUBY_ENGINE == 'ruby' && \
9
- RUBY_PLATFORM =~ /darwin|linux|bsd/ && \
10
- RUBY_VERSION # "1.9.3"
11
- .split('.') # ["1", "9", "3"]
12
- .map(&:to_i) # [1, 9, 3]
13
- .zip([2, 3, -1]) # [[1, 2], [9, 3], [3, -1]]
14
- .map { |a, b| a <=> b } # [-1, 1, 1]
15
- .detect { |e| !e.zero? } # -1
16
- .==(1) # false
7
+ enable_cc =
8
+ RUBY_ENGINE == 'ruby' &&
9
+ RUBY_PLATFORM =~ /darwin|linux|bsd/ &&
10
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.3.0")
17
11
 
18
12
  cache_dir = ENV['BOOTSNAP_CACHE_DIR']
19
13
  unless cache_dir
@@ -1,3 +1,3 @@
1
1
  module Bootsnap
2
- VERSION = "1.1.5"
2
+ VERSION = "1.1.6"
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.1.5
4
+ version: 1.1.6
5
5
  platform: java
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-06 00:00:00.000000000 Z
11
+ date: 2017-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,7 @@ files:
120
120
  - ext/bootsnap/bootsnap.h
121
121
  - ext/bootsnap/extconf.rb
122
122
  - lib/bootsnap.rb
123
+ - lib/bootsnap/bundler.rb
123
124
  - lib/bootsnap/compile_cache.rb
124
125
  - lib/bootsnap/compile_cache/iseq.rb
125
126
  - lib/bootsnap/compile_cache/yaml.rb