diff --git a/.github/matrix-full.yml b/.github/matrix-full.yml index 1fda136c8756..e8379aa5160c 100644 --- a/.github/matrix-full.yml +++ b/.github/matrix-full.yml @@ -53,7 +53,8 @@ build-packages: package: rpm package-type: aws2 check-manifest-suite: amazonlinux-2-amd64 - bazel-args: --platforms=//:aws2-crossbuild-x86_64 + # simdjson doesn't compile on gcc7.3.1 (needs 7.4) + bazel-args: --platforms=//:aws2-crossbuild-x86_64 --//:simdjson=False - label: amazonlinux-2023 image: amazonlinux:2023 package: rpm diff --git a/.requirements b/.requirements index a1eaae28ff81..989ac21cbfb5 100644 --- a/.requirements +++ b/.requirements @@ -16,6 +16,7 @@ LIBEXPAT_SHA256=d4cf38d26e21a56654ffe4acd9cd5481164619626802328506a2869afab29ab3 LUA_KONG_NGINX_MODULE=a8411f7cf4289049f0bd3e8e40088e7256389ed3 # 0.11.0 LUA_RESTY_LMDB=7d2581cbe30cde18a8482d820c227ca0845c0ded # 1.4.2 LUA_RESTY_EVENTS=2dcd1d7a256c53103c0fdbe804f419174e0ea8ba # 0.3.0 +LUA_RESTY_SIMDJSON=b861c98d50ab75b6c2fc6e875a5ea23143dc4157 # 1.0.0 LUA_RESTY_WEBSOCKET=966c69c39f03029b9b42ec0f8e55aaed7d6eebc0 # 0.4.0.1 ATC_ROUTER=ffd11db657115769bf94f0c4f915f98300bc26b6 # 1.6.2 SNAPPY=23b3286820105438c5dbb9bc22f1bb85c5812c8a # 1.2.0 diff --git a/BUILD.bazel b/BUILD.bazel index c2c6c21c39e1..20c265c370ea 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -127,6 +127,20 @@ config_setting( visibility = ["//visibility:public"], ) +# --//:simdjson=true +bool_flag( + name = "simdjson", + build_setting_default = True, +) + +config_setting( + name = "simdjson_flag", + flag_values = { + ":simdjson": "true", + }, + visibility = ["//visibility:public"], +) + # --//:licensing=false bool_flag( name = "licensing", diff --git a/WORKSPACE b/WORKSPACE index ae97c320d94e..32663c411a20 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -40,6 +40,10 @@ load("//build/nfpm:repositories.bzl", "nfpm_repositories") nfpm_repositories() +load("@simdjson_ffi//build:repos.bzl", "simdjson_ffi_repositories") + +simdjson_ffi_repositories() + load("@atc_router//build:repos.bzl", "atc_router_repositories") atc_router_repositories() diff --git a/build/BUILD.bazel b/build/BUILD.bazel index 715a9e194d79..008a71ffce57 100644 --- a/build/BUILD.bazel +++ b/build/BUILD.bazel @@ -83,6 +83,11 @@ lualib_deps = [ "@atc_router//:lualib_srcs", ] +# TODO: merge into luaclib_deps once amazonlinux2 support is dropped +lualib_conditional_deps = [ + "@simdjson_ffi//:lualib_srcs", +] + [ kong_install( name = "install-%s-lualib" % get_workspace_name(k), @@ -95,13 +100,18 @@ lualib_deps = [ ] else "/lib" ), ) - for k in lualib_deps + for k in lualib_deps + lualib_conditional_deps ] luaclib_deps = [ "@atc_router", ] +# TODO: merge into luaclib_deps once amazonlinux2 support is dropped +luaclib_conditional_deps = [ + "@simdjson_ffi", +] + [ kong_install( name = "install-%s-luaclib" % get_workspace_name(k), @@ -109,7 +119,7 @@ luaclib_deps = [ prefix = "openresty/site/lualib", strip_path = get_workspace_name(k), ) - for k in luaclib_deps + for k in luaclib_deps + luaclib_conditional_deps ] kong_rules_group( @@ -120,7 +130,13 @@ kong_rules_group( ] + [ "install-%s-luaclib" % get_workspace_name(k) for k in luaclib_deps - ], + ] + select({ + "@kong//:simdjson_flag": [ + ":install-simdjson_ffi-lualib", + ":install-simdjson_ffi-luaclib", + ], + "//conditions:default": [], + }), ) # WasmX diff --git a/build/openresty/repositories.bzl b/build/openresty/repositories.bzl index 0d992fd3fd99..3b01aa23901c 100644 --- a/build/openresty/repositories.bzl +++ b/build/openresty/repositories.bzl @@ -6,6 +6,7 @@ load("//build:build_system.bzl", "git_or_local_repository") load("@kong_bindings//:variables.bzl", "KONG_VAR") load("//build/openresty/pcre:pcre_repositories.bzl", "pcre_repositories") load("//build/openresty/openssl:openssl_repositories.bzl", "openssl_repositories") +load("//build/openresty/simdjson_ffi:simdjson_ffi_repositories.bzl", "simdjson_ffi_repositories") load("//build/openresty/atc_router:atc_router_repositories.bzl", "atc_router_repositories") load("//build/openresty/wasmx:wasmx_repositories.bzl", "wasmx_repositories") load("//build/openresty/wasmx/filters:repositories.bzl", "wasm_filters_repositories") @@ -30,6 +31,7 @@ filegroup( def openresty_repositories(): pcre_repositories() openssl_repositories() + simdjson_ffi_repositories() atc_router_repositories() wasmx_repositories() wasm_filters_repositories() diff --git a/build/openresty/simdjson_ffi/BUILD.bazel b/build/openresty/simdjson_ffi/BUILD.bazel new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/build/openresty/simdjson_ffi/simdjson_ffi_repositories.bzl b/build/openresty/simdjson_ffi/simdjson_ffi_repositories.bzl new file mode 100644 index 000000000000..0d9649c9560c --- /dev/null +++ b/build/openresty/simdjson_ffi/simdjson_ffi_repositories.bzl @@ -0,0 +1,11 @@ +"""A module defining the dependency lua-resty-simdjson""" + +load("//build:build_system.bzl", "git_or_local_repository") +load("@kong_bindings//:variables.bzl", "KONG_VAR") + +def simdjson_ffi_repositories(): + git_or_local_repository( + name = "simdjson_ffi", + branch = KONG_VAR["LUA_RESTY_SIMDJSON"], + remote = "https://github.com/Kong/lua-resty-simdjson", + ) diff --git a/changelog/unreleased/kong/resty-simdjson.yml b/changelog/unreleased/kong/resty-simdjson.yml new file mode 100644 index 000000000000..2da90247be21 --- /dev/null +++ b/changelog/unreleased/kong/resty-simdjson.yml @@ -0,0 +1,5 @@ +message: | + Introduced a yieldable JSON library `lua-resty-simdjson`, + which would improve the latency significantly. +type: dependency +scope: Core diff --git a/kong/clustering/control_plane.lua b/kong/clustering/control_plane.lua index 6bdfb24e192a..990eb5ec346b 100644 --- a/kong/clustering/control_plane.lua +++ b/kong/clustering/control_plane.lua @@ -3,7 +3,6 @@ local _MT = { __index = _M, } local semaphore = require("ngx.semaphore") -local cjson = require("cjson.safe") local declarative = require("kong.db.declarative") local clustering_utils = require("kong.clustering.utils") local compat = require("kong.clustering.compat") @@ -20,8 +19,8 @@ local pairs = pairs local ngx = ngx local ngx_log = ngx.log local timer_at = ngx.timer.at -local cjson_decode = cjson.decode -local cjson_encode = cjson.encode +local json_decode = clustering_utils.json_decode +local json_encode = clustering_utils.json_encode local kong = kong local ngx_exit = ngx.exit local exiting = ngx.worker.exiting @@ -121,7 +120,7 @@ function _M:export_deflated_reconfigure_payload() -- store serialized plugins map for troubleshooting purposes local shm_key_name = "clustering:cp_plugins_configured:worker_" .. (worker_id() or -1) - kong_dict:set(shm_key_name, cjson_encode(self.plugins_configured)) + kong_dict:set(shm_key_name, json_encode(self.plugins_configured)) ngx_log(ngx_DEBUG, "plugin configuration map key: ", shm_key_name, " configuration: ", kong_dict:get(shm_key_name)) local config_hash, hashes = calculate_config_hash(config_table) @@ -136,7 +135,7 @@ function _M:export_deflated_reconfigure_payload() self.reconfigure_payload = payload - payload, err = cjson_encode(payload) + payload, err = json_encode(payload) if not payload then return nil, err end @@ -207,7 +206,7 @@ function _M:handle_cp_websocket(cert) err = "failed to receive websocket basic info data" else - data, err = cjson_decode(data) + data, err = json_decode(data) if type(data) ~= "table" then err = "failed to decode websocket basic info data" .. (err and ": " .. err or "") diff --git a/kong/clustering/data_plane.lua b/kong/clustering/data_plane.lua index f6621c2a2341..35ae9161f270 100644 --- a/kong/clustering/data_plane.lua +++ b/kong/clustering/data_plane.lua @@ -3,7 +3,6 @@ local _MT = { __index = _M, } local semaphore = require("ngx.semaphore") -local cjson = require("cjson.safe") local config_helper = require("kong.clustering.config_helper") local clustering_utils = require("kong.clustering.utils") local declarative = require("kong.db.declarative") @@ -18,8 +17,8 @@ local sub = string.sub local ngx = ngx local ngx_log = ngx.log local ngx_sleep = ngx.sleep -local cjson_decode = cjson.decode -local cjson_encode = cjson.encode +local json_decode = clustering_utils.json_decode +local json_encode = clustering_utils.json_encode local exiting = ngx.worker.exiting local ngx_time = ngx.time local inflate_gzip = require("kong.tools.gzip").inflate_gzip @@ -111,7 +110,7 @@ end ---@param err_t kong.clustering.config_helper.update.err_t ---@param log_suffix? string local function send_error(c, err_t, log_suffix) - local payload, json_err = cjson_encode({ + local payload, json_err = json_encode({ type = "error", error = err_t, }) @@ -121,7 +120,7 @@ local function send_error(c, err_t, log_suffix) ngx_log(ngx_ERR, _log_prefix, "failed to JSON-encode error payload for ", "control plane: ", json_err, ", payload: ", inspect(err_t), log_suffix) - payload = assert(cjson_encode({ + payload = assert(json_encode({ type = "error", error = { name = constants.CLUSTERING_DATA_PLANE_ERROR.GENERIC, @@ -180,11 +179,11 @@ function _M:communicate(premature) -- The CP will make the decision on whether sync will be allowed -- based on the received information local _ - _, err = c:send_binary(cjson_encode({ type = "basic_info", - plugins = self.plugins_list, - process_conf = configuration, - filters = self.filters, - labels = labels, })) + _, err = c:send_binary(json_encode({ type = "basic_info", + plugins = self.plugins_list, + process_conf = configuration, + filters = self.filters, + labels = labels, })) if err then ngx_log(ngx_ERR, _log_prefix, "unable to send basic information to control plane: ", uri, " err: ", err, " (retrying after ", reconnection_delay, " seconds)", log_suffix) @@ -238,7 +237,7 @@ function _M:communicate(premature) local msg = assert(inflate_gzip(data)) yield() - msg = assert(cjson_decode(msg)) + msg = assert(json_decode(msg)) yield() if msg.type ~= "reconfigure" then diff --git a/kong/clustering/utils.lua b/kong/clustering/utils.lua index 0ac9c8e69265..092b368ee83b 100644 --- a/kong/clustering/utils.lua +++ b/kong/clustering/utils.lua @@ -155,6 +155,7 @@ function _M.connect_dp(dp_id, dp_hostname, dp_ip, dp_version) return wb, log_suffix end + function _M.is_dp_worker_process() if kong.configuration.role == "data_plane" and kong.configuration.dedicated_config_processing == true then @@ -164,4 +165,33 @@ function _M.is_dp_worker_process() return worker_id() == 0 end + +-- encode/decode json with cjson or simdjson +local ok, simdjson_dec = pcall(require, "resty.simdjson.decoder") +if not ok or kong.configuration.cluster_cjson then + local cjson = require("cjson.safe") + + _M.json_decode = cjson.decode + _M.json_encode = cjson.encode + +else + _M.json_decode = function(str) + -- enable yield and not reentrant for decode + local dec = simdjson_dec.new(true) + + local res, err = dec:process(str) + dec:destroy() + + return res, err + end + + -- enable yield and reentrant for encode + local enc = require("resty.simdjson.encoder").new(true) + + _M.json_encode = function(obj) + return enc:process(obj) + end +end + + return _M diff --git a/kong/conf_loader/constants.lua b/kong/conf_loader/constants.lua index dbf0cb6def91..59bd482cce66 100644 --- a/kong/conf_loader/constants.lua +++ b/kong/conf_loader/constants.lua @@ -499,6 +499,7 @@ local CONF_PARSERS = { cluster_use_proxy = { typ = "boolean" }, cluster_dp_labels = { typ = "array" }, cluster_rpc = { typ = "boolean" }, + cluster_cjson = { typ = "boolean" }, kic = { typ = "boolean" }, pluginserver_names = { typ = "array" }, diff --git a/kong/templates/kong_defaults.lua b/kong/templates/kong_defaults.lua index 6a33c351d3a0..b03980d9fb97 100644 --- a/kong/templates/kong_defaults.lua +++ b/kong/templates/kong_defaults.lua @@ -42,6 +42,7 @@ cluster_max_payload = 16777216 cluster_use_proxy = off cluster_dp_labels = NONE cluster_rpc = off +cluster_cjson = off lmdb_environment_path = dbless.lmdb lmdb_map_size = 2048m diff --git a/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt b/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt index b940c8e8889f..7b5c7a0bf8ec 100644 --- a/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt +++ b/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt @@ -199,3 +199,10 @@ - ld-linux-x86-64.so.2 - libstdc++.so.6 - libm.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt b/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt index 193dd354ecd7..dc4f126bab70 100644 --- a/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt +++ b/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt @@ -203,3 +203,11 @@ Needed : - libgcc_s.so.1 - libc.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libm.so.6 + - libstdc++.so.6 + - libgcc_s.so.1 + - libc.so.6 + - ld-linux-aarch64.so.1 diff --git a/scripts/explain_manifest/fixtures/debian-11-amd64.txt b/scripts/explain_manifest/fixtures/debian-11-amd64.txt index 846b95ad5a6d..7647cdfb4f13 100644 --- a/scripts/explain_manifest/fixtures/debian-11-amd64.txt +++ b/scripts/explain_manifest/fixtures/debian-11-amd64.txt @@ -202,3 +202,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/debian-12-amd64.txt b/scripts/explain_manifest/fixtures/debian-12-amd64.txt index 1ab0eabe5b16..ebeb6014fe24 100644 --- a/scripts/explain_manifest/fixtures/debian-12-amd64.txt +++ b/scripts/explain_manifest/fixtures/debian-12-amd64.txt @@ -189,3 +189,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/el8-amd64.txt b/scripts/explain_manifest/fixtures/el8-amd64.txt index ca3351b3a11a..629859f3ca62 100644 --- a/scripts/explain_manifest/fixtures/el8-amd64.txt +++ b/scripts/explain_manifest/fixtures/el8-amd64.txt @@ -212,3 +212,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/el9-amd64.txt b/scripts/explain_manifest/fixtures/el9-amd64.txt index 7457649228b5..d1b29e97cb7f 100644 --- a/scripts/explain_manifest/fixtures/el9-amd64.txt +++ b/scripts/explain_manifest/fixtures/el9-amd64.txt @@ -199,3 +199,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/el9-arm64.txt b/scripts/explain_manifest/fixtures/el9-arm64.txt index 193dd354ecd7..dc4f126bab70 100644 --- a/scripts/explain_manifest/fixtures/el9-arm64.txt +++ b/scripts/explain_manifest/fixtures/el9-arm64.txt @@ -203,3 +203,11 @@ Needed : - libgcc_s.so.1 - libc.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libm.so.6 + - libstdc++.so.6 + - libgcc_s.so.1 + - libc.so.6 + - ld-linux-aarch64.so.1 diff --git a/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt b/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt index 41172c077810..dcaa0ef9271d 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt @@ -206,3 +206,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt b/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt index bee32048e1f7..60d62a4563c6 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt @@ -193,3 +193,10 @@ - libc.so.6 - ld-linux-x86-64.so.2 - libstdc++.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libm.so.6 + - libgcc_s.so.1 + - libc.so.6 diff --git a/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt b/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt index 916b90bf1d39..0d875dde28b0 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt @@ -191,3 +191,10 @@ Needed : - libgcc_s.so.1 - libc.so.6 + +- Path : /usr/local/openresty/site/lualib/libsimdjson_ffi.so + Needed : + - libstdc++.so.6 + - libgcc_s.so.1 + - libc.so.6 + - ld-linux-aarch64.so.1 diff --git a/spec/01-unit/31-simdjson/01-cjson_compatibility_spec.lua b/spec/01-unit/31-simdjson/01-cjson_compatibility_spec.lua new file mode 100644 index 000000000000..584954f94138 --- /dev/null +++ b/spec/01-unit/31-simdjson/01-cjson_compatibility_spec.lua @@ -0,0 +1,284 @@ +local helpers = require("spec.helpers") +local cjson = require("cjson.safe") +local simdjson = require("resty.simdjson") + + +local deep_sort = helpers.deep_sort + + +describe("[cjson compatibility] examples from cjson repo", function () + + local strs = { +[[ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Mark up Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} +]], + +[[ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} +]], + +[[ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} +]], + +[[ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} +]], + +[[ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} +]], + +[[ +[ 0.110001, + 0.12345678910111, + 0.412454033640, + 2.6651441426902, + 2.718281828459, + 3.1415926535898, + 2.1406926327793 +] +]], + +[[ +{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } +} +]], + +[[ +[ + { + "precision": "zip", + "Latitude": 37.7668, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" + }, + { + "precision": "zip", + "Latitude": 37.371991, + "Longitude": -122.026020, + "Address": "", + "City": "SUNNYVALE", + "State": "CA", + "Zip": "94085", + "Country": "US" + } +] +]], + } + + it("runs with unified interface", function () + + local parser = simdjson.new() + assert(parser) + + for _, str in ipairs(strs) do + local obj1 = parser:decode(str) + local obj2 = cjson.decode(parser:encode(obj1)) + assert.same(deep_sort(obj1), deep_sort(obj2)) + end + + parser:destroy() + end) + + it("runs with separated interface", function () + + local dec = require("resty.simdjson.decoder").new() + local enc = require("resty.simdjson.encoder").new() + + assert(dec and enc) + + for _, str in ipairs(strs) do + local obj1 = dec:process(str) + local obj2 = cjson.decode(enc:process(obj1)) + assert.same(deep_sort(obj1), deep_sort(obj2)) + end + + dec:destroy() + end) + +end) diff --git a/spec/helpers.lua b/spec/helpers.lua index 8e27875ccc00..bdcb04cf13ef 100644 --- a/spec/helpers.lua +++ b/spec/helpers.lua @@ -2461,6 +2461,11 @@ local deep_sort do return deep_compare(a[1], b[1]) end + -- compare cjson.null or ngx.null + if type(a) == "userdata" and type(b) == "userdata" then + return false + end + return a < b end