leventov commented on a change in pull request #8157: Enum of ResponseContext 
keys
URL: https://github.com/apache/incubator-druid/pull/8157#discussion_r309841059
 
 

 ##########
 File path: 
processing/src/main/java/org/apache/druid/query/context/ResponseContext.java
 ##########
 @@ -76,56 +253,158 @@ public static ResponseContext createEmpty()
     return DefaultResponseContext.createEmpty();
   }
 
-  protected abstract Map<String, Object> getDelegate();
+  /**
+   * Deserializes a string into {@link ResponseContext} using given {@link 
ObjectMapper}.
+   * @throws IllegalStateException if one of the deserialized map keys has not 
been registered.
+   */
+  public static ResponseContext deserialize(String responseContext, 
ObjectMapper objectMapper) throws IOException
+  {
+    final Map<String, Object> keyNameToObjects = objectMapper.readValue(
+        responseContext,
+        JacksonUtils.TYPE_REFERENCE_MAP_STRING_OBJECT
+    );
+    final ResponseContext context = ResponseContext.createEmpty();
+    keyNameToObjects.forEach((keyName, value) -> {
+      final BaseKey key = Key.keyOf(keyName);
+      context.add(key, value);
+    });
+    return context;
+  }
+
+  protected abstract Map<BaseKey, Object> getDelegate();
 
-  public Object put(String key, Object value)
+  /**
+   * Associates the specified object with the specified key.
+   * @throws IllegalStateException if the key has not been registered.
+   */
+  public Object put(BaseKey key, Object value)
   {
-    return getDelegate().put(key, value);
+    final BaseKey registeredKey = Key.keyOf(key.getName());
+    return getDelegate().put(registeredKey, value);
   }
 
-  public Object get(String key)
+  public Object get(BaseKey key)
   {
     return getDelegate().get(key);
   }
 
-  public Object remove(String key)
+  public Object remove(BaseKey key)
   {
     return getDelegate().remove(key);
   }
 
-  public void putAll(Map<? extends String, ?> m)
+  /**
+   * Adds (merges) a new value associated with a key to an old value.
+   * See merge function of a context key for a specific implementation.
+   * @throws IllegalStateException if the key has not been registered.
+   */
+  public Object add(BaseKey key, Object value)
   {
-    getDelegate().putAll(m);
+    final BaseKey registeredKey = Key.keyOf(key.getName());
+    return getDelegate().merge(registeredKey, value, key.getMergeFunction());
   }
 
-  public void putAll(ResponseContext responseContext)
+  /**
+   * Merges a response context into the current.
+   * @throws IllegalStateException If a key of the {@code responseContext} has 
not been registered.
+   */
+  public void merge(ResponseContext responseContext)
   {
-    getDelegate().putAll(responseContext.getDelegate());
+    responseContext.getDelegate().forEach((key, newValue) -> {
+      if (newValue != null) {
+        add(key, newValue);
+      }
+    });
   }
 
-  public int size()
+  /**
+   * Serializes the context given that the resulting string length is less 
than the provided limit.
+   * This method tries to remove some elements from context collections if 
it's needed to satisfy the limit.
+   * The resulting string might be correctly deserialized to {@link 
ResponseContext}.
+   */
+  public SerializationResult serializeWith(ObjectMapper objectMapper, int 
maxCharsNumber) throws JsonProcessingException
   {
-    return getDelegate().size();
+    final String fullSerializedString = 
objectMapper.writeValueAsString(getDelegate());
+    if (fullSerializedString.length() <= maxCharsNumber) {
+      return new SerializationResult(fullSerializedString, 
fullSerializedString);
+    } else {
+      // Indicates that the context is truncated during serialization.
+      add(Key.TRUNCATED, true);
+      final ObjectNode contextJsonNode = 
objectMapper.valueToTree(getDelegate());
+      final ArrayList<Map.Entry<String, JsonNode>> sortedNodesByLength = 
Lists.newArrayList(contextJsonNode.fields());
+      final Comparator<Map.Entry<String, JsonNode>> 
valueLengthReversedComparator =
+          Comparator.comparing((Map.Entry<String, JsonNode> e) -> 
e.getValue().toString().length()).reversed();
+      sortedNodesByLength.sort(valueLengthReversedComparator);
+      int needToRemoveCharsNumber = fullSerializedString.length() - 
maxCharsNumber;
+      // The complexity of this block is O(n*m*log(m)) where n - context size, 
m - context's array size
+      for (Map.Entry<String, JsonNode> e : sortedNodesByLength) {
+        final String fieldName = e.getKey();
+        final JsonNode node = e.getValue();
+        if (node.isArray()) {
+          if (needToRemoveCharsNumber >= node.toString().length()) {
+            final int lengthBeforeRemove = node.toString().length();
+            // Empty array could be correctly deserialized so we remove only 
its elements.
+            ((ArrayNode) node).removeAll();
+            final int lengthAfterRemove = node.toString().length();
+            needToRemoveCharsNumber -= lengthBeforeRemove - lengthAfterRemove;
+          } else {
+            final ArrayNode arrNode = (ArrayNode) node;
 
 Review comment:
   This block needs a comment. It's not obvious what and why is going on here. 
Please extract as a method (or the upper block) if possible.

----------------------------------------------------------------
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.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@druid.apache.org
For additional commands, e-mail: commits-h...@druid.apache.org

Reply via email to