You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@geode.apache.org by "Kirk Lund (Jira)" <ji...@apache.org> on 2022/03/08 17:45:00 UTC

[jira] [Comment Edited] (GEODE-10112) Add ConcurrentHashMap support to DataSerializer

    [ https://issues.apache.org/jira/browse/GEODE-10112?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17503080#comment-17503080 ] 

Kirk Lund edited comment on GEODE-10112 at 3/8/22, 5:44 PM:
------------------------------------------------------------

Some initial feedback from [~jbarrett]:

We should not be serializing specific types of Map at all. Type specific serialization causes issues when trying to deserialize on non-Java systems and make migrations to different, maybe more performant, Map implementations more complicated.

We should have a writeMap(DataOutput out, Map<?. ?> map) and <K, V> Map<K, V> readMap(DatatInput in) and maybe a <K, V> Map<K, V> readMap(DatatInput in, Map<K, V> map) that will utilize the pre-constructed map for deserialization directly. Additionally I would argue for <M extends Map<K, V>, K, V> M readMap(DataInput in, MapConstructor mapConstructor) for optimizing the construction for the size of the map.
{noformat}
  @FunctionalInterface
  public interface MapConstructor<M extends Map<K, V>, K, V> {
    M construct(int size);
  }

  public static <M extends Map<K, V>, K, V> M readMap(DataInput in, MapConstructor<M, K, V> mapConstructor)
      throws IOException, ClassNotFoundException {
    InternalDataSerializer.checkIn(in);

    int size = InternalDataSerializer.readArrayLength(in);
    if (size == -1) {
      return null;
    } else {
      M map = mapConstructor.construct(size);
      for (int i = 0; i < size; i++) {
        K key = DataSerializer.readObject(in);
        V value = DataSerializer.readObject(in);
        map.put(key, value);
      }

      if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
        logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Map with {} elements: {}", size, map);
      }

      return map;
    }
  }
{noformat}
The legacy readHashMap:
{noformat}
  public static <K, V> HashMap<K, V> readHashMap(DataInput in)
      throws IOException, ClassNotFoundException {
    return readMap(in, HashMap::new);
  }
{noformat}
And to read a ConcurrentHashMap:
{noformat}
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    ConcurrentHashMap<String, String> map = readMap(in, ConcurrentHashMap::new);
    ...
  }
{noformat}
Because someday maybe we need to do this change the type to something faster:
{noformat}
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    SuperFastConcurrentHashMap<String, String> map = readMap(in, SuperFastConcurrentHashMap::new);
    ...
  }
{noformat}
Without this generic Map capability we are stuck with:
{noformat}
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    SuperFastConcurrentHashMap<String, String> map = new SuperFastConcurrentHashMap(readConcurrentHashMap(in);
    ...
  }
{noformat}
Which has the unfortunately side affect of deserializing to a types we can’t use then populating the type that we want.


was (Author: klund):
Some initial feedback from [~jbarrett]:

We should not be serializing specific types of Map at all. Type specific serialization causes issues when trying to deserialize on non-Java systems and make migrations to different, maybe more performant, Map implementations more complicated.

We should have a writeMap(DataOutput out, Map<?. ?> map) and <K, V> Map<K, V> readMap(DatatInput in) and maybe a <K, V> Map<K, V> readMap(DatatInput in, Map<K, V> map) that will utilize the pre-constructed map for deserialization directly. Additionally I would argue for <M extends Map<K, V>, K, V> M readMap(DataInput in, MapConstructor mapConstructor) for optimizing the construction for the size of the map.
{{{
  @FunctionalInterface
  public interface MapConstructor<M extends Map<K, V>, K, V> {
    M construct(int size);
  }

  public static <M extends Map<K, V>, K, V> M readMap(DataInput in, MapConstructor<M, K, V> mapConstructor)
      throws IOException, ClassNotFoundException {
    InternalDataSerializer.checkIn(in);

    int size = InternalDataSerializer.readArrayLength(in);
    if (size == -1) {
      return null;
    } else {
      M map = mapConstructor.construct(size);
      for (int i = 0; i < size; i++) {
        K key = DataSerializer.readObject(in);
        V value = DataSerializer.readObject(in);
        map.put(key, value);
      }

      if (logger.isTraceEnabled(LogMarker.SERIALIZER_VERBOSE)) {
        logger.trace(LogMarker.SERIALIZER_VERBOSE, "Read Map with {} elements: {}", size, map);
      }

      return map;
    }
  }
}}}
The legacy readHashMap:
{{{
  public static <K, V> HashMap<K, V> readHashMap(DataInput in)
      throws IOException, ClassNotFoundException {
    return readMap(in, HashMap::new);
  }
}}}
And to read a ConcurrentHashMap:
{{{
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    ConcurrentHashMap<String, String> map = readMap(in, ConcurrentHashMap::new);
    ...
  }
}}}
Because someday maybe we need to do this change the type to something faster:
{{{
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    SuperFastConcurrentHashMap<String, String> map = readMap(in, SuperFastConcurrentHashMap::new);
    ...
  }
}}}
Without this generic Map capability we are stuck with:
{{{
  public void someMethod(DataInput in)
      throws IOException, ClassNotFoundException {
    SuperFastConcurrentHashMap<String, String> map = new SuperFastConcurrentHashMap(readConcurrentHashMap(in);
    ...
  }
}}}
Which has the unfortunately side affect of deserializing to a types we can’t use then populating the type that we want.

> Add ConcurrentHashMap support to DataSerializer
> -----------------------------------------------
>
>                 Key: GEODE-10112
>                 URL: https://issues.apache.org/jira/browse/GEODE-10112
>             Project: Geode
>          Issue Type: Improvement
>          Components: wan
>            Reporter: Kirk Lund
>            Assignee: Kirk Lund
>            Priority: Major
>              Labels: GeodeOperationAPI
>
> Add ConcurrentHashMap support to DataSerializer. This will improve performance of Gateway messages that have fields related to regionToDispatchedKeysMap which contain values of type ConcurrentHashMap. Messages include ParallelQueueRemovalMessage.



--
This message was sent by Atlassian Jira
(v8.20.1#820001)