bootsnap 1.1.5-java → 1.1.6-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
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