[njs] Modules: removed extra VM creation per server.
noreply at nginx.com
noreply at nginx.com
Mon Jan 6 23:53:02 UTC 2025
details: https://github.com/nginx/njs/commit/855aa4c9fac01bd9fbdb1602b523edc00117ff09
branches: master
commit: 855aa4c9fac01bd9fbdb1602b523edc00117ff09
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri, 3 Jan 2025 22:25:15 -0800
description:
Modules: removed extra VM creation per server.
Previously, when js_import was declared in http or stream blocks, an extra
copy of the VM instance was created for each server block. This was not
needed and consumed a lot of memory for configurations with many server
blocks.
This issue was introduced in 9b674412 (0.8.6) and was
partially fixed for location blocks only in 685b64f0 (0.8.7).
---
nginx/ngx_js.c | 17 ++++++++
nginx/t/js_import2.t | 12 +++++-
nginx/t/js_merge_location_blocks.t | 83 ++++++++++++++++++++++++++++++++++++++
nginx/t/js_merge_server_blocks.t | 78 +++++++++++++++++++++++++++++++++++
nginx/t/stream_js.t | 6 ++-
5 files changed, 194 insertions(+), 2 deletions(-)
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c
index 12b577a2..5c2a44cb 100644
--- a/nginx/ngx_js.c
+++ b/nginx/ngx_js.c
@@ -3343,6 +3343,16 @@ ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
ngx_array_t *imports, *preload_objects, *paths;
ngx_js_named_path_t *import, *pi, *pij, *preload;
+ if (prev->imports != NGX_CONF_UNSET_PTR && prev->engine == NULL) {
+ /*
+ * special handling to preserve conf->engine
+ * in the "http" or "stream" section to inherit it to all servers
+ */
+ if (init_vm(cf, (ngx_js_loc_conf_t *) prev) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
if (conf->imports == NGX_CONF_UNSET_PTR
&& conf->type == prev->type
&& conf->paths == NGX_CONF_UNSET_PTR
@@ -3851,6 +3861,9 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
return NGX_ERROR;
}
+ ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, "js vm init %s: %p",
+ conf->engine->name, conf->engine);
+
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_ERROR;
@@ -4039,6 +4052,10 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
ngx_js_loc_conf_t *conf = child;
ngx_conf_merge_uint_value(conf->type, prev->type, NGX_ENGINE_NJS);
+ if (prev->type == NGX_CONF_UNSET_UINT) {
+ prev->type = NGX_ENGINE_NJS;
+ }
+
ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
ngx_conf_merge_size_value(conf->reuse, prev->reuse, 128);
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384);
diff --git a/nginx/t/js_import2.t b/nginx/t/js_import2.t
index cd29d2dc..7fdc624d 100644
--- a/nginx/t/js_import2.t
+++ b/nginx/t/js_import2.t
@@ -41,6 +41,7 @@ http {
js_set $test foo.bar.p;
+ # context 1
js_import foo from main.js;
location /njs {
@@ -52,11 +53,13 @@ http {
}
location /test_lib {
+ # context 2
js_import lib.js;
js_content lib.test;
}
location /test_fun {
+ # context 3
js_import fun.js;
js_content fun;
}
@@ -75,6 +78,7 @@ http {
server_name localhost;
location /test_fun {
+ # context 4
js_import fun.js;
js_content fun;
}
@@ -114,7 +118,7 @@ $t->write_file('main.js', <<EOF);
EOF
-$t->try_run('no njs available')->plan(5);
+$t->try_run('no njs available')->plan(6);
###############################################################################
@@ -124,4 +128,10 @@ like(http_get('/test_fun'), qr/FUN-TEST/s, 'fun');
like(http_get('/proxy/test_fun'), qr/FUN-TEST/s, 'proxy fun');
like(http_get('/test_var'), qr/P-TEST/s, 'foo.bar.p');
+$t->stop();
+
+my $content = $t->read_file('error.log');
+my $count = () = $content =~ m/js vm init/g;
+ok($count == 4, 'uniq js vm contexts');
+
###############################################################################
diff --git a/nginx/t/js_merge_location_blocks.t b/nginx/t/js_merge_location_blocks.t
new file mode 100644
index 00000000..328d5338
--- /dev/null
+++ b/nginx/t/js_merge_location_blocks.t
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+# (C) Dmitry Volyntsev
+# (c) Nginx, Inc.
+
+# Tests for http njs module, check for proper location blocks merging.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http/)
+ ->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ js_import main.js;
+
+ server {
+ listen 127.0.0.1:8080;
+ server_name localhost;
+
+ location /a {
+ js_content main.version;
+ }
+
+ location /b {
+ js_content main.version;
+ }
+
+ location /c {
+ js_content main.version;
+ }
+
+ location /d {
+ js_content main.version;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('main.js', <<EOF);
+ function version(r) {
+ r.return(200, njs.version);
+ }
+
+ export default {version};
+
+EOF
+
+$t->try_run('no njs available')->plan(1);
+
+###############################################################################
+
+$t->stop();
+
+my $content = $t->read_file('error.log');
+my $count = () = $content =~ m/ js vm init/g;
+ok($count == 1, 'http js block imported once');
+
+###############################################################################
diff --git a/nginx/t/js_merge_server_blocks.t b/nginx/t/js_merge_server_blocks.t
new file mode 100644
index 00000000..c3f261af
--- /dev/null
+++ b/nginx/t/js_merge_server_blocks.t
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+
+# (C) Dmitry Volyntsev
+# (c) Nginx, Inc.
+
+# Tests for http njs module, check for proper server blocks merging.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http/)
+ ->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ js_import main.js;
+
+ server {
+ listen 127.0.0.1:8080;
+ }
+
+ server {
+ listen 127.0.0.1:8081;
+ }
+
+ server {
+ listen 127.0.0.1:8082;
+ }
+
+ server {
+ listen 127.0.0.1:8083;
+ }
+}
+
+EOF
+
+$t->write_file('main.js', <<EOF);
+ function version(r) {
+ r.return(200, njs.version);
+ }
+
+ export default {version};
+
+EOF
+
+$t->try_run('no njs available')->plan(1);
+
+###############################################################################
+
+$t->stop();
+
+my $content = $t->read_file('error.log');
+my $count = () = $content =~ m/ js vm init/g;
+ok($count == 1, 'http js block imported once');
+
+###############################################################################
diff --git a/nginx/t/stream_js.t b/nginx/t/stream_js.t
index 52ab688e..0834b68a 100644
--- a/nginx/t/stream_js.t
+++ b/nginx/t/stream_js.t
@@ -394,7 +394,7 @@ $t->write_file('test.js', <<EOF);
EOF
$t->run_daemon(\&stream_daemon, port(8090));
-$t->try_run('no stream njs available')->plan(24);
+$t->try_run('no stream njs available')->plan(25);
$t->waitforsocket('127.0.0.1:' . port(8090));
###############################################################################
@@ -450,6 +450,10 @@ like($t->read_file('status.log'), qr/$p[0]:200/, 'status undecided');
like($t->read_file('status.log'), qr/$p[1]:200/, 'status allow');
like($t->read_file('status.log'), qr/$p[2]:403/, 'status deny');
+my $content = $t->read_file('error.log');
+my $count = () = $content =~ m/ js vm init/g;
+ok($count == 2, 'http and stream js blocks imported once each');
+
###############################################################################
sub has_version {
More information about the nginx-devel
mailing list