You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by "pavel-ptashyts (via GitHub)" <gi...@apache.org> on 2026/10/05 14:19:16 UTC
[I] [Java] Strings are written one character at a time from the first character that needs escaping to the end (java, fory-json) [fory]
pavel-ptashyts opened a new issue, #4121:
URL: https://github.com/apache/fory/issues/4121
### What happens
This is the writing side of #4055. In `fory-json`, once a string being written contains its first character that
needs escaping, the rest of that string is written one character at a time. The scan that found the character is
never resumed, so the cost of writing a string is proportional to the distance from its **first** such character to
its end, not to the number of characters that need escaping.
On objects dominated by one large string with a few quotes or newlines in it, this makes writing an order of
magnitude slower than writing the same string without them.
### Where
`main` at `f85877f2`, both writers:
- `org/apache/fory/json/writer/Utf8JsonWriter.java`
- A compact latin1 `String` longer than the fixed-size fast paths that contains any byte to escape is rejected
by `writeLongLatin1StringNoEnsure` and goes to `writeStringChars`, which scans it with `charAt`, four
characters at a time, up to the first stop.
- From there `writeStringSlow` writes every remaining character through `writeEscapedChar`: a switch, a
capacity check and one store per character, and it never returns to a bulk copy. The `CharSequence`
overload and the UTF16 `String` path end in the same loop.
- `org/apache/fory/json/writer/StringJsonWriter.java` - the same shape in all four tails:
`writeLatin1StringSlow` and `writeLatin1StringUtf16Slow` for compact latin1 input, `writeStringSlow` and
`writeStringUtf16Slow` for character input.
### Measurements
Standalone harness, JDK 25.0.2, `ForyJson.builder().build()`, best of 7 rounds of 5000 writes after 30000 warm-up
writes per variant. The object is a bid with a 19998-character `adm` string holding VAST XML, pure ASCII, 612
quotes and 345 newlines, the **first** quote at character 15. The cause is isolated by changing only the
characters that need escaping inside `adm`, keeping its length:
| variant | `toJsonBytes` | `toJson` |
|---|---:|---:|
| nothing to escape | 3.9 us | 3.6 us |
| one quote at the very end | 19.6 us | 3.6 us |
| one quote at character 1 | 49.7 us | 38.0 us |
| the real string | 46.9 us | 43.6 us |
With nothing to escape the 20 KB string is written in 3.9 us. One quote near the front costs 13 times that, the
same as all 957 of them, because everything after it is written character by character. For `toJsonBytes` even a
quote at the very end costs 5 times, because the whole string is first rescanned character by character up to it.
For reference, Jackson 3.1 `writeValueAsString` on the same object takes 12.5 us without escapes and 25.0 us on
the real string.
### Suggested fix
The same shape as #4058, local to the slow paths and leaving the fixed-size fast paths in `writeString` untouched:
1. In `Utf8JsonWriter`, send a compact latin1 string that the fast paths reject to a loop over its bytes that
copies each plain run a word at a time with the existing `isJsonAsciiWord` predicate, writes the one byte that
stopped it through `writeEscapedChar`, and resumes.
2. In every character tail of both writers, copy the run of plain characters up to the next stop with one
capacity check per run, then handle the stop character exactly as now. In `StringJsonWriter` the run follows
the current output coder, since a character above `0xFF` upgrades the output to UTF16 in the middle of a string.
Measured with that applied to `main`, same harness, output byte-identical in every variant:
| variant | `toJsonBytes` | `toJson` |
|---|---:|---:|
| nothing to escape | 3.9 us | 3.5 us |
| one quote at the very end | 6.0 us | 3.4 us |
| one quote at character 1 | 4.5 us | 3.8 us |
| the real string | 10.3 us | 11.8 us |
I have the patch and will open a pull request against `main`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org
Re: [I] [Java] Strings are written one character at a time from the first character that needs escaping to the end (java, fory-json) [fory]
Posted by "chaokunyang (via GitHub)" <gi...@apache.org>.
chaokunyang closed issue #4121: [Java] Strings are written one character at a time from the first character that needs escaping to the end (java, fory-json)
URL: https://github.com/apache/fory/issues/4121
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org