|
19 | 19 |
|
20 | 20 | #include "src/request_body_processor/json_backend.h" |
21 | 21 |
|
| 22 | +#include <algorithm> |
22 | 23 | #include <chrono> |
23 | 24 | #include <cstdint> |
| 25 | +#include <memory> |
24 | 26 | #include <string> |
25 | 27 | #include <utility> |
26 | 28 |
|
@@ -87,6 +89,51 @@ JsonParseResult fromSimdjsonError(simdjson::error_code error) { |
87 | 89 | } |
88 | 90 | } |
89 | 91 |
|
| 92 | +simdjson::ondemand::parser &getReusableSimdjsonParser() { |
| 93 | + thread_local std::unique_ptr<simdjson::ondemand::parser> parser; |
| 94 | + if (parser == nullptr) { |
| 95 | +#ifdef MSC_JSON_AUDIT_INSTRUMENTATION |
| 96 | + const auto parser_start = std::chrono::steady_clock::now(); |
| 97 | + parser.reset(new simdjson::ondemand::parser()); |
| 98 | + recordSimdjsonParserConstruction(static_cast<std::uint64_t>( |
| 99 | + std::chrono::duration_cast<std::chrono::nanoseconds>( |
| 100 | + std::chrono::steady_clock::now() - parser_start).count())); |
| 101 | +#else |
| 102 | + parser.reset(new simdjson::ondemand::parser()); |
| 103 | +#endif |
| 104 | + } |
| 105 | + return *parser; |
| 106 | +} |
| 107 | + |
| 108 | +std::size_t clampRequestedMaxDepth(std::size_t input_size, |
| 109 | + const JsonBackendParseOptions &options) { |
| 110 | + const std::size_t requested_depth = options.technical_max_depth > 0 |
| 111 | + ? static_cast<std::size_t>(options.technical_max_depth) : 1; |
| 112 | + const std::size_t max_possible_depth = (input_size / 2) + 1; |
| 113 | + return std::min(requested_depth, std::max<std::size_t>(1, |
| 114 | + max_possible_depth)); |
| 115 | +} |
| 116 | + |
| 117 | +simdjson::error_code prepareParser(simdjson::ondemand::parser *parser, |
| 118 | + std::size_t input_size, const JsonBackendParseOptions &options) { |
| 119 | + if (parser == nullptr) { |
| 120 | + return simdjson::MEMALLOC; |
| 121 | + } |
| 122 | + |
| 123 | + const JsonBackendParseOptions default_options; |
| 124 | + std::size_t required_max_depth = parser->max_depth(); |
| 125 | + if (options.technical_max_depth != default_options.technical_max_depth) { |
| 126 | + required_max_depth = clampRequestedMaxDepth(input_size, options); |
| 127 | + } |
| 128 | + |
| 129 | + if (parser->capacity() >= input_size |
| 130 | + && parser->max_depth() == required_max_depth) { |
| 131 | + return simdjson::SUCCESS; |
| 132 | + } |
| 133 | + |
| 134 | + return parser->allocate(input_size, required_max_depth); |
| 135 | +} |
| 136 | + |
90 | 137 | template <typename ResultType, typename TargetType> |
91 | 138 | JsonParseResult getResult(ResultType &&result, TargetType *target) { |
92 | 139 | if (auto error = std::forward<ResultType>(result).get(*target); error) { |
@@ -361,26 +408,23 @@ class JsonBackendWalker { |
361 | 408 |
|
362 | 409 | JsonParseResult parseDocumentWithSimdjson(const std::string &input, |
363 | 410 | JsonEventSink *sink, const JsonBackendParseOptions &options) { |
364 | | - (void) options; |
365 | | - |
366 | 411 | if (sink == nullptr) { |
367 | 412 | return makeResult(JsonParseStatus::InternalError, |
368 | 413 | JsonSinkStatus::InternalError, "JSON event sink is null."); |
369 | 414 | } |
370 | 415 |
|
| 416 | + simdjson::ondemand::parser &parser = getReusableSimdjsonParser(); |
| 417 | + if (auto error = prepareParser(&parser, input.size(), options); error) { |
| 418 | + return fromSimdjsonError(error); |
| 419 | + } |
| 420 | + |
371 | 421 | #ifdef MSC_JSON_AUDIT_INSTRUMENTATION |
372 | | - const auto parser_start = std::chrono::steady_clock::now(); |
373 | | - simdjson::ondemand::parser parser; |
374 | | - recordSimdjsonParserConstruction(static_cast<std::uint64_t>( |
375 | | - std::chrono::duration_cast<std::chrono::nanoseconds>( |
376 | | - std::chrono::steady_clock::now() - parser_start).count())); |
377 | 422 | const auto padded_start = std::chrono::steady_clock::now(); |
378 | 423 | simdjson::padded_string padded(input); |
379 | 424 | recordSimdjsonPaddedCopy(input.size(), static_cast<std::uint64_t>( |
380 | 425 | std::chrono::duration_cast<std::chrono::nanoseconds>( |
381 | 426 | std::chrono::steady_clock::now() - padded_start).count())); |
382 | 427 | #else |
383 | | - simdjson::ondemand::parser parser; |
384 | 428 | simdjson::padded_string padded(input); |
385 | 429 | #endif |
386 | 430 | simdjson::ondemand::document document; |
|
0 commit comments