[JAVA-2986] Improve performance of the legacy JSON parse by not calling containsField("$...") for arrays Created: 20/Sep/18 Updated: 11/Oct/18 Resolved: 11/Oct/18 |
|
| Status: | Closed |
| Project: | Java Driver |
| Component/s: | JSON |
| Affects Version/s: | 3.6.4 |
| Fix Version/s: | None |
| Type: | Improvement | Priority: | Major - P3 |
| Reporter: | Chris Reed | Assignee: | Unassigned |
| Resolution: | Won't Fix | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Backwards Compatibility: | Fully Compatible |
| Description |
|
Profiling our use case showed a lot of time being spent with callstacks as per the below - throwing exceptions in parsing JSON.
What seems to be happening is we have a JSONCallback which we call arrayDone on. That's not implemented by JSONCallback, but by BasicBSONCallback implements arrayDone() by calling objectDone(). There's some attempt to skip the bulk of JSONCallback.objectDone if the last object was an array with the _lastArray member of JSONCallback, but that's flawed - if you have an array of objects, you'll get callbacks:
Rather than this messing about with _lastArray, surely implementing arrayDone() as super.arrayDone (so that BasicBSONCallback can maintain its stack state) would be simpler and more correct - and avoid the below problem? Currently, when parsing an array of objects, we execute all of JSONCallback.objectDone for the array, calling containsField("$...") for each of the supported Extended JSON attributes. The implementation of BasicBSONList is to attempt to parse its argument as an Integer, which throws an exception. This is problematic, as creating exceptions is expensive (as it happens, this was 200 stack frames down, so each exception's fillInStackTrace as its created is quite expensive...)
(An alternative fix is to make BasicBSONList.containsField check the first character - if it's not in the range 0..9, then just return false - bypassing the exception codepath for this common case)
at java.lang.Throwable.fillInStackTrace(Native Method) at java.lang.Throwable.fillInStackTrace(Throwable.java:783) - locked <0x000000073da6fd40> (a java.lang.NumberFormatException) at java.lang.Throwable.<init>(Throwable.java:265) at java.lang.Exception.<init>(Exception.java:54) at java.lang.RuntimeException.<init>(RuntimeException.java:62) at java.lang.IllegalArgumentException.<init>(IllegalArgumentException.java:52) at java.lang.NumberFormatException.<init>(NumberFormatException.java:55) at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:569) at java.lang.Integer.parseInt(Integer.java:615) at org.bson.types.BasicBSONList._getInt(BasicBSONList.java:165) at org.bson.types.BasicBSONList.containsField(BasicBSONList.java:135) at com.mongodb.util.JSONCallback.objectDone(JSONCallback.java:130) at org.bson.BasicBSONCallback.arrayDone(BasicBSONCallback.java:139) at com.mongodb.util.JSONParser.parseArray(JSON.java:628) at com.mongodb.util.JSONParser.parse(JSON.java:224) at com.mongodb.util.JSONParser.parseObject(JSON.java:264) at com.mongodb.util.JSONParser.parse(JSON.java:228) at com.mongodb.util.JSONParser.parse(JSON.java:156) at com.mongodb.util.JSON.parse(JSON.java:98) at com.mongodb.util.JSON.parse(JSON.java:79) |
| Comments |
| Comment by Jeffrey Yemin [ 11/Oct/18 ] |
|
The JSON class is deprecated and will be removed in the next major release, so we're not going to invest time in its improvement. Users of the JSON class should migrate to JsonReader at their earliest convenience. |