Bug #86894 Inefficient string management in JSON quoting
Submitted: 1 Jul 2017 14:22 Modified: 4 Jan 2018 17:59
Reporter: Alexey Kopytov Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: JSON Severity:S3 (Non-critical)
Version:5.7 OS:Any
Assigned to: CPU Architecture:Any

[1 Jul 2017 14:22] Alexey Kopytov
Description:
double_quote() is used to convert JSON documents from internal
representation to a user-visible string. Since certain characters have
to be escaped, the resulting string may be longer than the original one.

To amortize buffer reallocation costs, double_quote() calls the
reserve() wrapper function every time it wants to append something to
the output string (i.e. when processing every character from the
original buffer).

The only purpose of the reserve() wrapper is to grow the buffer
exponentially rather than linearly for cases when reallocations are
frequent. Which is completely redundant, because String::append()
implements a similar technique and is used by double_quote() to append
data to the output buffer. See comments for String::mem_realloc_exp().

On a read-only benchmark consisting of reading 1K JSON documents by
primary key, reserve() is called millions times per second, wasting
about 3% of CPU time.

How to repeat:
Look at the reserve() function in sql/json_dom.cc. Compare with
String::mem_realloc_exp() in sql/sql_string.cc

Suggested fix:
Remove all reserve() calls from double_quote(), except the first
one. Other functions in json_dom.cc may need similar fixes,
e.g. print_string() and wrapper_to_string().
[1 Jul 2017 20:45] Alexey Kopytov
I noticed that exactly this problem has been fixed in 8.0 with the following commit:

commit 76161d5e4b3cdb5793af30a151a5bece4e9345d0
Author: Knut Anders Hatlen <knut.hatlen@oracle.com>
Date:   Fri Dec 18 10:52:38 2015 +0100

    Bug#22284168: REMOVE NOW REDUNDANT SPACE RESERVATION IN JSON_DOM.CC
    
    json_dom.cc has code to make Strings grow exponentially instead of
    linearly. Bug#22239803 made String::append() grow the string buffer
    exponentially by default, so this code is redundant now.
    
    This patch removes manual growing of Strings in json_dom.cc. There are
    a couple of exceptions: We still reserve space manually in cases where
    data is added directly into the internal buffer without going through
    String::append().

Fix for Bug#22239803 is present in 5.7, so this is a request to backport fix for Bug#22284168 to 5.7.
[3 Jul 2017 5:56] MySQL Verification Team
Hello Alexey,

Thank you for the report.
Verifying for the request to backport fix for Bug#22284168 to 5.7.

Thanks,
Umesh
[4 Jan 2018 17:56] Knut Anders Hatlen
Posted by developer:
 
Bug#22284168 has been backported to 5.7 as part of WL#11065. Will be fixed in 5.7.22.