Hi Niels,
I think WeakHashMap is used because it's onwed by GenericData which is a
singleton.
So, Fields should be "weak reference" to allow garbaging when field is
removed.

As comment says

// this MAY result in two threads creating the same defaultValue
// and calling put. The last thread will win. However,
// that's not an issue.
defaultValueCache.put(field, defaultValue);

So, it's even not a pb if Map is not synchronized.
In both case, usage of computeIfAbsent is better.

Le ven. 10 févr. 2023 à 13:16, Niels Basjes <ni...@basjes.nl> a écrit :

> Hi,
>
> Earlier this week a few colleagues of mine ran into a concurrency problem
> in Avro which is a regression of the fix applied in
> https://issues.apache.org/jira/browse/AVRO-1760.
>
> I created a new ticket to track this
> https://issues.apache.org/jira/browse/AVRO-3713
>
> Summary of the problem:
> In 2016 this change was made to solve the concurrency problem (too much
> synchronization/locking):
> *Original code:*
>
>   private final Map<Field, Object> defaultValueCache
>     = Collections.synchronizedMap(new WeakHashMap<Field, Object>());
>
> *New code (using Guava):*
>
>   private final Map<Field, Object> defaultValueCache
>     = new MapMaker().weakKeys().makeMap();
>
> Then in 2018 guava was dropped
> *New code:*
>
>   private final Map<Field, Object> defaultValueCache
>     = Collections.synchronizedMap(new WeakHashMap<>());
>
> So we are back where we started and the same problem has returned.
>
> Looking at this last code change I found that when dropping Guava in many
> places a ConcurrentHashMap is used.
> Only in this place because of the "Weak Keys" a different setup was used.
>
> I looked back into the version history and this code dates back to 2013 (
> https://issues.apache.org/jira/browse/AVRO-1228 ) .
> I found no explanation about why the weak keys are used (I checked Jira,
> Mailing list and the code).
>
> My question is simply: *Why use weak keys? Is that really needed?*
>
> If we do not need it I propose to simply go for a ConcurrentHashMap.
> If we do need it I think the fix should probably look something like this:
>
> private final WeakConcurrentMap<Field, Object> defaultValueCache = new
> WeakConcurrentMap<>();
>
> private static class WeakConcurrentMap<K, V> {
>   ConcurrentHashMap<WeakReference<K>, V> map = new ConcurrentHashMap<>();
>
>   public V get(K key) {
>     WeakReference<K> weakKey = new WeakReference<>(key);
>     V value = map.get(weakKey);
>     if(value != null) {
>       return value;
>     } else {
>       map.remove(weakKey);
>       return null;
>     }
>   }
>
>   V put(K key, V value) {
>     return map.put(new WeakReference<>(key), value);
>   }
> }
>
>
>
>
> --
> Best regards / Met vriendelijke groeten,
>
> Niels Basjes
>

Reply via email to