[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:

  • arrayStart (sets _lastArray = true)
  • objectStart (sets _lastArray = false)
  • objectDone
  • arrayDone -> objectDone (_lastArray is false)

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.

Generated at Thu Feb 08 08:58:31 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.