Skip to content

Commit

Permalink
Fix #3311: essentially backporting #1994 from 3.0 to establish limit …
Browse files Browse the repository at this point in the history
…on serializer cache
  • Loading branch information
cowtowncoder committed Jul 1, 2022
1 parent f3ba2d9 commit 08a27c9
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.fasterxml.jackson.databind.ser;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.impl.ReadOnlyClassToSerializerMap;
import com.fasterxml.jackson.databind.util.LRUMap;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
Expand All @@ -24,22 +24,34 @@
*/
public final class SerializerCache
{
/**
* By default, allow caching of up to 4000 serializer entries (for possibly up to
* 1000 types; but depending access patterns may be as few as half of that).
*/
public final static int DEFAULT_MAX_CACHED = 4000;

/**
* Shared, modifiable map; all access needs to be through synchronized blocks.
*<p>
* NOTE: keys are of various types (see below for key types), in addition to
* basic {@link JavaType} used for "untyped" serializers.
*/
private final HashMap<TypeKey, JsonSerializer<Object>> _sharedMap
= new HashMap<TypeKey, JsonSerializer<Object>>(64);
private final LRUMap<TypeKey, JsonSerializer<Object>> _sharedMap;

/**
* Most recent read-only instance, created from _sharedMap, if any.
*/
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap
= new AtomicReference<ReadOnlyClassToSerializerMap>();
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap;

public SerializerCache() { }
public SerializerCache() {
this(DEFAULT_MAX_CACHED);
}

public SerializerCache(int maxCached) {
int initial = Math.min(64, maxCached>>2);
_sharedMap = new LRUMap<TypeKey, JsonSerializer<Object>>(initial, maxCached);
_readOnlyMap = new AtomicReference<ReadOnlyClassToSerializerMap>();
}

/**
* Method that can be called to get a read-only instance populated from the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.fasterxml.jackson.databind.ser.impl;

import java.util.*;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.util.LRUMap;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
Expand All @@ -23,17 +22,15 @@ public final class ReadOnlyClassToSerializerMap

private final int _mask;

public ReadOnlyClassToSerializerMap(Map<TypeKey,JsonSerializer<Object>> serializers)
public ReadOnlyClassToSerializerMap(LRUMap<TypeKey,JsonSerializer<Object>> src)
{
int size = findSize(serializers.size());
_size = size;
_mask = (size-1);
Bucket[] buckets = new Bucket[size];
for (Map.Entry<TypeKey,JsonSerializer<Object>> entry : serializers.entrySet()) {
TypeKey key = entry.getKey();
_size = findSize(src.size());
_mask = (_size-1);
Bucket[] buckets = new Bucket[_size];
src.contents((key, value) -> {
int index = key.hashCode() & _mask;
buckets[index] = new Bucket(buckets[index], key, entry.getValue());
}
buckets[index] = new Bucket(buckets[index], key, value);
});
_buckets = buckets;
}

Expand All @@ -51,7 +48,7 @@ private final static int findSize(int size)
/**
* Factory method for constructing an instance.
*/
public static ReadOnlyClassToSerializerMap from(HashMap<TypeKey, JsonSerializer<Object>> src) {
public static ReadOnlyClassToSerializerMap from(LRUMap<TypeKey, JsonSerializer<Object>> src) {
return new ReadOnlyClassToSerializerMap(src);
}

Expand Down
19 changes: 17 additions & 2 deletions src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.fasterxml.jackson.databind.util;

import java.util.Map;
import java.util.function.BiConsumer;

import com.fasterxml.jackson.databind.util.internal.PrivateMaxEntriesMap;

/**
Expand Down Expand Up @@ -61,9 +64,21 @@ public V putIfAbsent(K key, V value) {
public int size() { return _map.size(); }

/*
/**********************************************************
/**********************************************************************
/* Extended API (2.14)
/**********************************************************************
*/

public void contents(BiConsumer<K,V> consumer) {
for (Map.Entry<K,V> entry : _map.entrySet()) {
consumer.accept(entry.getKey(), entry.getValue());
}
}

/*
/**********************************************************************
/* Serializable overrides
/**********************************************************
/**********************************************************************
*/

protected Object readResolve() {
Expand Down

0 comments on commit 08a27c9

Please sign in to comment.