From 2d02be597712707f01bb78101969867b93f2eca9 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Tue, 10 Feb 2015 22:40:38 -0800 Subject: [PATCH 1/7] add REQUIRE_CACHE_{READ_WRITE} env vars --- load.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- vm.c | 3 +++ vm_core.h | 6 ++++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/load.c b/load.c index f31b7aeaca961b..74740e6bd0a560 100644 --- a/load.c +++ b/load.c @@ -944,6 +944,7 @@ rb_require_safe(VALUE fname, int safe) { volatile VALUE result = Qnil; rb_thread_t *th = GET_THREAD(); + rb_vm_t *vm = GET_VM(); volatile VALUE errinfo = th->errinfo; int state; struct { @@ -960,9 +961,11 @@ rb_require_safe(VALUE fname, int safe) PUSH_TAG(); saved.safe = rb_safe_level(); if ((state = EXEC_TAG()) == 0) { - VALUE path; + VALUE ipath, path; long handle; int found; + st_data_t key, val; + char *vals; rb_set_safe_level_force(safe); FilePathValue(fname); @@ -974,8 +977,26 @@ rb_require_safe(VALUE fname, int safe) rb_sourceline()); } - path = rb_str_encode_ospath(fname); - found = search_required(path, &path, safe); + ipath = rb_str_encode_ospath(fname); + if (vm->require_cache.read && RSTRING_PTR(ipath)[0] != '/') { + key = (st_data_t)RSTRING_PTR(ipath); + if (st_delete(vm->require_cache.tbl, &key, &val)) { + vals = (char *)val; + if ((found = vals[0])) { + //fprintf(stderr, "FOUND '%s' => '%s'\n", (char *)key, vals); + path = rb_str_new_cstr(vals+1); + } + xfree(vals); + } else { + found = search_required(ipath, &path, safe); + } + } else { + found = search_required(ipath, &path, safe); + } + if (vm->require_cache.write && RSTRING_PTR(ipath)[0] != '/' && path) { + fprintf(vm->require_cache.out, "%s\n%c%s\n", RSTRING_PTR(ipath), found ? found : '\0', found ? RSTRING_PTR(path) : ""); + fsync(fileno(vm->require_cache.out)); + } if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) { RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname), @@ -1154,6 +1175,34 @@ rb_f_autoload_p(VALUE obj, VALUE sym) return rb_mod_autoload_p(klass, sym); } +void +require_cache_setup() +{ + rb_vm_t *vm = GET_VM(); + FILE *file; + char *env, line1[PATH_MAX+3], line2[PATH_MAX+3]; + + if ((env = getenv("REQUIRE_CACHE_READ"))) { + file = fopen(env, "r"); + if (!file) return; + + vm->require_cache.read = 1; + vm->require_cache.tbl = st_init_strtable(); + while (1) { + if (!fgets(line1, PATH_MAX+2, file)) break; + if (!fgets(line2, PATH_MAX+2, file)) break; + line1[strlen(line1)-1] = 0; + line2[strlen(line2)-1] = 0; + //fprintf(stderr, "INSERTING '%s' => '%s'\n", line1, line2); + st_insert(vm->require_cache.tbl, (st_data_t)ruby_strdup(line1), (st_data_t)ruby_strdup(line2)); + } + fclose(file); + } else if ((env = getenv("REQUIRE_CACHE_WRITE"))) { + vm->require_cache.write = 1; + vm->require_cache.out = fopen(env, "w"); + } +} + void Init_load() { @@ -1187,4 +1236,6 @@ Init_load() ruby_dln_librefs = rb_ary_tmp_new(0); rb_gc_register_mark_object(ruby_dln_librefs); + + require_cache_setup(); } diff --git a/vm.c b/vm.c index 212f7b01401f68..cb8456bbf96c5a 100644 --- a/vm.c +++ b/vm.c @@ -1823,6 +1823,9 @@ ruby_vm_destruct(rb_vm_t *vm) #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE struct rb_objspace *objspace = vm->objspace; #endif + if (vm->require_cache.write) + fclose(vm->require_cache.out); + rb_gc_force_recycle(vm->self); vm->main_thread = 0; if (th) { diff --git a/vm_core.h b/vm_core.h index 73127e65eab41d..a19bba74e3f627 100644 --- a/vm_core.h +++ b/vm_core.h @@ -377,6 +377,12 @@ typedef struct rb_vm_struct { VALUE loaded_features_snapshot; struct st_table *loaded_features_index; struct st_table *loading_table; + struct { + unsigned int read:1; + struct st_table *tbl; + unsigned int write:1; + FILE *out; + } require_cache; /* signal */ struct { From 25e98f767546b8aef78f751f6973c684f9899eaf Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Wed, 11 Feb 2015 00:17:11 -0800 Subject: [PATCH 2/7] cache lookup failures too --- load.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/load.c b/load.c index 74740e6bd0a560..f34f43aa876915 100644 --- a/load.c +++ b/load.c @@ -961,7 +961,7 @@ rb_require_safe(VALUE fname, int safe) PUSH_TAG(); saved.safe = rb_safe_level(); if ((state = EXEC_TAG()) == 0) { - VALUE ipath, path; + VALUE ipath, path = 0; long handle; int found; st_data_t key, val; @@ -982,19 +982,29 @@ rb_require_safe(VALUE fname, int safe) key = (st_data_t)RSTRING_PTR(ipath); if (st_delete(vm->require_cache.tbl, &key, &val)) { vals = (char *)val; - if ((found = vals[0])) { - //fprintf(stderr, "FOUND '%s' => '%s'\n", (char *)key, vals); + found = vals[0]; + if (found) { + /*fprintf(stderr, "FOUND '%s' => '%s'\n", (char *)key, vals);*/ path = rb_str_new_cstr(vals+1); } xfree(vals); } else { found = search_required(ipath, &path, safe); + /*if (found && path) + fprintf(stderr, "MISSING '%s' => '%s'\n", RSTRING_PTR(ipath), RSTRING_PTR(path));*/ } } else { found = search_required(ipath, &path, safe); + /*if (found && RSTRING_PTR(ipath)[0] != '/') + fprintf(stderr, "SEARCHING '%s'\n", RSTRING_PTR(ipath));*/ } - if (vm->require_cache.write && RSTRING_PTR(ipath)[0] != '/' && path) { - fprintf(vm->require_cache.out, "%s\n%c%s\n", RSTRING_PTR(ipath), found ? found : '\0', found ? RSTRING_PTR(path) : ""); + if (vm->require_cache.write && RSTRING_PTR(ipath)[0] != '/' && (!found || (found && path))) { + /*fprintf(stderr, "WRITING '%s' => '%s'\n", RSTRING_PTR(ipath), found ? RSTRING_PTR(path) : "");*/ + fprintf(vm->require_cache.out, "%s\n", RSTRING_PTR(ipath)); + if (found) + fprintf(vm->require_cache.out, "%c%s\n", found, RSTRING_PTR(path)); + else + fprintf(vm->require_cache.out, "%s\n", ""); fsync(fileno(vm->require_cache.out)); } @@ -1193,7 +1203,7 @@ require_cache_setup() if (!fgets(line2, PATH_MAX+2, file)) break; line1[strlen(line1)-1] = 0; line2[strlen(line2)-1] = 0; - //fprintf(stderr, "INSERTING '%s' => '%s'\n", line1, line2); + /*fprintf(stderr, "INSERTING '%s' => '%s'\n", line1, line2);*/ st_insert(vm->require_cache.tbl, (st_data_t)ruby_strdup(line1), (st_data_t)ruby_strdup(line2)); } fclose(file); From bbbca3c045d0df24b93614d6ccd784e8399f18f1 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Wed, 11 Feb 2015 18:06:37 -0800 Subject: [PATCH 3/7] clear out REQUIRE_CACHE_WRITE for any subprocesses --- load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/load.c b/load.c index f34f43aa876915..e52840c508b6b7 100644 --- a/load.c +++ b/load.c @@ -1208,6 +1208,7 @@ require_cache_setup() } fclose(file); } else if ((env = getenv("REQUIRE_CACHE_WRITE"))) { + unsetenv("REQUIRE_CACHE_WRITE", ""); vm->require_cache.write = 1; vm->require_cache.out = fopen(env, "w"); } From c9721f4f4c7294dd0f07043846770c59bdbbae1f Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Wed, 11 Feb 2015 18:06:45 -0800 Subject: [PATCH 4/7] change debug msg --- load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/load.c b/load.c index e52840c508b6b7..2c92a233ba467e 100644 --- a/load.c +++ b/load.c @@ -995,8 +995,8 @@ rb_require_safe(VALUE fname, int safe) } } else { found = search_required(ipath, &path, safe); - /*if (found && RSTRING_PTR(ipath)[0] != '/') - fprintf(stderr, "SEARCHING '%s'\n", RSTRING_PTR(ipath));*/ + /*if (found && path) + fprintf(stderr, "SEARCHING '%s' found '%s'\n", RSTRING_PTR(ipath), RSTRING_PTR(path));*/ } if (vm->require_cache.write && RSTRING_PTR(ipath)[0] != '/' && (!found || (found && path))) { /*fprintf(stderr, "WRITING '%s' => '%s'\n", RSTRING_PTR(ipath), found ? RSTRING_PTR(path) : "");*/ From 1089cf1f707ca22c5fb7ad53271e5aafc89994bc Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Wed, 11 Feb 2015 18:39:58 -0800 Subject: [PATCH 5/7] use st_lookup instead of st_delete, and emulate search_required behavior --- load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/load.c b/load.c index 2c92a233ba467e..fa225faafa1bd4 100644 --- a/load.c +++ b/load.c @@ -980,14 +980,14 @@ rb_require_safe(VALUE fname, int safe) ipath = rb_str_encode_ospath(fname); if (vm->require_cache.read && RSTRING_PTR(ipath)[0] != '/') { key = (st_data_t)RSTRING_PTR(ipath); - if (st_delete(vm->require_cache.tbl, &key, &val)) { + if (st_lookup(vm->require_cache.tbl, key, &val)) { vals = (char *)val; found = vals[0]; if (found) { /*fprintf(stderr, "FOUND '%s' => '%s'\n", (char *)key, vals);*/ path = rb_str_new_cstr(vals+1); + vals[1] = 0; } - xfree(vals); } else { found = search_required(ipath, &path, safe); /*if (found && path) From 8afbab473b170761a8588ff83fac6cfc649cfa15 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Thu, 5 Mar 2015 17:29:40 -0800 Subject: [PATCH 6/7] short circuit require("enumerator") --- load.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/load.c b/load.c index fa225faafa1bd4..0da98bc5d14067 100644 --- a/load.c +++ b/load.c @@ -952,6 +952,9 @@ rb_require_safe(VALUE fname, int safe) } volatile saved; char *volatile ftptr = 0; + if (strncmp(StringValuePtr(fname), "enumerator", 11) == 0) + return Qfalse; + if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname), rb_sourcefile(), From faa994cf6b62bb95ec498e6b3dd194a055bb00be Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Thu, 5 Mar 2015 17:37:07 -0800 Subject: [PATCH 7/7] ignore READ variable in WRITE mode --- load.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/load.c b/load.c index 0da98bc5d14067..2ddeb11c8ea00d 100644 --- a/load.c +++ b/load.c @@ -1195,7 +1195,11 @@ require_cache_setup() FILE *file; char *env, line1[PATH_MAX+3], line2[PATH_MAX+3]; - if ((env = getenv("REQUIRE_CACHE_READ"))) { + if ((env = getenv("REQUIRE_CACHE_WRITE"))) { + unsetenv("REQUIRE_CACHE_WRITE", ""); + vm->require_cache.write = 1; + vm->require_cache.out = fopen(env, "w"); + } else if ((env = getenv("REQUIRE_CACHE_READ"))) { file = fopen(env, "r"); if (!file) return; @@ -1210,10 +1214,6 @@ require_cache_setup() st_insert(vm->require_cache.tbl, (st_data_t)ruby_strdup(line1), (st_data_t)ruby_strdup(line2)); } fclose(file); - } else if ((env = getenv("REQUIRE_CACHE_WRITE"))) { - unsetenv("REQUIRE_CACHE_WRITE", ""); - vm->require_cache.write = 1; - vm->require_cache.out = fopen(env, "w"); } }