summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lehnardt <jan@apache.org>2022-12-13 14:54:36 +0100
committerGitHub <noreply@github.com>2022-12-13 14:54:36 +0100
commit99a8f666c8b9d1f5a6ebbb09c83e59e1916c0205 (patch)
treefe4595e6b1bc63bbc9c979013968059d0a7b4bda
parent641586116fc6f78228f203c04e8eca9660e2027f (diff)
downloadcouchdb-99a8f666c8b9d1f5a6ebbb09c83e59e1916c0205.tar.gz
fix(3517): super-simplistic fix to avoid costly AST transforms when t… (#4292)
* fix(3517): super-simplistic fix to avoid costly AST transforms when they are not needed Co-authored-by: Ronny Berndt <ronny@apache.org>
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--Makefile.win2
-rw-r--r--rel/reltool.config1
-rw-r--r--share/server/60/rewrite_fun.js5
-rw-r--r--share/server/60/rewrite_fun_ast_bypass.js61
-rw-r--r--src/docs/src/config/query-servers.rst13
-rw-r--r--support/build_js.escript15
8 files changed, 92 insertions, 8 deletions
diff --git a/.gitignore b/.gitignore
index 816ece6d4..7c2b9f189 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ rel/dev*
rel/tmpdata
share/server/main-coffee.js
share/server/main.js
+share/server/main-ast-bypass.js
share/www
src/bear/
src/certifi/
diff --git a/Makefile b/Makefile
index 34562d1b9..522acaf39 100644
--- a/Makefile
+++ b/Makefile
@@ -442,7 +442,7 @@ clean:
@rm -rf src/*/.rebar
@rm -rf src/*/priv/*.so
@rm -rf src/couch/priv/{couchspawnkillable,couchjs}
- @rm -rf share/server/main.js share/server/main-coffee.js
+ @rm -rf share/server/main.js share/server/main-ast-bypass.js share/server/main-coffee.js
@rm -rf tmp dev/data dev/lib dev/logs
@rm -rf src/mango/.venv
@rm -f src/couch/priv/couchspawnkillable
diff --git a/Makefile.win b/Makefile.win
index 5bbfeead9..8a8129ff8 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -374,7 +374,7 @@ clean:
-@rmdir /s/q src\*\.rebar
-@del /f/q/s src\*.dll
-@del /f/q src\couch\priv\*.exe
- -@del /f/q share\server\main.js share\server\main-coffee.js
+ -@del /f/q share\server\main.js share\server\main-ast-bypass.js share\server\main-coffee.js
-@rmdir /s/q tmp
-@rmdir /s/q dev\data
-@rmdir /s/q dev\lib
diff --git a/rel/reltool.config b/rel/reltool.config
index ab26fb2ed..f7c9df14b 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
@@ -141,6 +141,7 @@
{copy, "overlay/etc"},
{copy, "../src/couch/priv/couchjs", "bin/couchjs"},
{copy, "../share/server/main.js", "share/server/main.js"},
+ {copy, "../share/server/main-ast-bypass.js", "share/server/main-ast-bypass.js"},
{copy, "../share/server/main-coffee.js", "share/server/main-coffee.js"},
{copy, "../src/weatherreport/weatherreport", "bin/weatherreport"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
diff --git a/share/server/60/rewrite_fun.js b/share/server/60/rewrite_fun.js
index 1b27a9d14..436fd3da1 100644
--- a/share/server/60/rewrite_fun.js
+++ b/share/server/60/rewrite_fun.js
@@ -28,7 +28,7 @@ function rewriteFunInt(fun) {
// If we have a function declaration without an Id, wrap it
// in an ExpressionStatement and change it into
- // a FuntionExpression
+ // a FunctionExpression
if (decl.type == "FunctionDeclaration" && decl.id == null) {
decl.type = "FunctionExpression";
ast.body[idx] = {
@@ -41,7 +41,6 @@ function rewriteFunInt(fun) {
return escodegen.generate(ast);
}
-
function rewriteFun(funJSON) {
const fun = JSON.parse(funJSON);
return JSON.stringify(rewriteFunInt(fun));
@@ -53,4 +52,4 @@ function rewriteFuns(funsJSON) {
return rewriteFunInt(fun);
});
return JSON.stringify(results);
-} \ No newline at end of file
+}
diff --git a/share/server/60/rewrite_fun_ast_bypass.js b/share/server/60/rewrite_fun_ast_bypass.js
new file mode 100644
index 000000000..d2c43caf1
--- /dev/null
+++ b/share/server/60/rewrite_fun_ast_bypass.js
@@ -0,0 +1,61 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+// Based on the normalizeFunction which can be
+// found here:
+//
+// https://github.com/dmunch/couch-chakra/blob/master/js/normalizeFunction.js
+
+function rewriteFunInt(fun) {
+ // Skip lengthy AST transforms if the function passed can be
+ // safely wrapped in parentheses.
+ if (fun.startsWith('function') && fun.endsWith('}')) {
+ return '(' + fun + ')'
+ }
+
+ const ast = esprima.parse(fun);
+ let idx = ast.body.length - 1;
+ let decl = {};
+
+ // Search for the first FunctionDeclaration beginning from the end
+ do {
+ decl = ast.body[idx--];
+ } while (idx >= 0 && decl.type !== "FunctionDeclaration");
+ idx++;
+
+ // If we have a function declaration without an Id, wrap it
+ // in an ExpressionStatement and change it into
+ // a FunctionExpression
+ if (decl.type == "FunctionDeclaration" && decl.id == null) {
+ decl.type = "FunctionExpression";
+ ast.body[idx] = {
+ type: "ExpressionStatement",
+ expression: decl
+ };
+ }
+
+ // Generate source from the rewritten AST
+ return escodegen.generate(ast);
+}
+
+function rewriteFun(funJSON) {
+ const fun = JSON.parse(funJSON);
+ return JSON.stringify(rewriteFunInt(fun));
+}
+
+function rewriteFuns(funsJSON) {
+ let funs = JSON.parse(funsJSON);
+ const results = Array.from(funs, (fun) => {
+ return rewriteFunInt(fun);
+ });
+ return JSON.stringify(results);
+}
diff --git a/src/docs/src/config/query-servers.rst b/src/docs/src/config/query-servers.rst
index 1d81665b8..3bd99c439 100644
--- a/src/docs/src/config/query-servers.rst
+++ b/src/docs/src/config/query-servers.rst
@@ -65,6 +65,19 @@ you can adjust the memory limitation (here, increasing to 512 MiB)::
For more info about the available options, please consult ``couchjs -h``.
+.. note::
+ CouchDB versions 3.0.0 to 3.2.2 included a performance regression for
+ custom reduce functions. CouchDB 3.3.0 and later come with an experimental
+ fix to this issue that is included in a separate ``.js`` file.
+
+ To enable the fix, you need to define a custom ``COUCHDB_QUERY_SERVER_JAVASCRIPT``
+ environment variable as outlined above. The path to ``couchjs`` needs to
+ remain the same as you find it on your ``couchdb`` file, and the path to
+ ``main.js`` needs to be set to ``/path/to/couchdb/share/server/main-ast-bypass.js``.
+
+ With a default installation on Linux systems, this is going to be
+ ``COUCHDB_QUERY_SERVER_JAVASCRIPT="/opt/couchdb/bin/couchjs /opt/couchdb/share/server/main-ast-bypass.js"``
+
.. _Mozilla SpiderMonkey: https://spidermonkey.dev/
.. seealso::
diff --git a/support/build_js.escript b/support/build_js.escript
index 5f1e92015..5ff45faed 100644
--- a/support/build_js.escript
+++ b/support/build_js.escript
@@ -68,11 +68,13 @@ main([]) ->
_ ->
[
"share/server/60/esprima.js",
- "share/server/60/escodegen.js",
- "share/server/60/rewrite_fun.js"
+ "share/server/60/escodegen.js"
]
end,
+ RewriteFunFile = ["share/server/60/rewrite_fun.js"],
+ RewriteFunWithASTBypassFile = ["share/server/60/rewrite_fun_ast_bypass.js"],
+
Pre = "(function () {\n",
Post = "})();\n",
@@ -85,6 +87,13 @@ main([]) ->
file:write_file(To, FinalBin)
end,
- ok = Concat(ExtraFiles ++ JsFiles, "share/server/main.js"),
+ case SMVsn of
+ "1.8.5" ->
+ ok = Concat(ExtraFiles ++ JsFiles, "share/server/main.js"),
+ ok = Concat(ExtraFiles ++ JsFiles, "share/server/main-ast-bypass.js");
+ _ ->
+ ok = Concat(RewriteFunFile ++ ExtraFiles ++ JsFiles, "share/server/main.js"),
+ ok = Concat(RewriteFunWithASTBypassFile ++ ExtraFiles ++ JsFiles, "share/server/main-ast-bypass.js")
+ end,
ok = Concat(ExtraFiles ++ CoffeeFiles, "share/server/main-coffee.js"),
ok.