Uploaded image for project: 'Java Driver'
  1. Java Driver
  2. JAVA-2986

Improve performance of the legacy JSON parse by not calling containsField("$...") for arrays

    • Type: Icon: Improvement Improvement
    • Resolution: Won't Fix
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 3.6.4
    • Component/s: JSON
    • Labels:
      None
    • Fully Compatible

      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)

            Assignee:
            Unassigned Unassigned
            Reporter:
            cree Chris Reed
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: