1
1
package com .fasterxml .jackson .databind .util ;
2
2
3
- import java .io .*;
4
- import java .util .concurrent .ConcurrentHashMap ;
3
+ import com .fasterxml .jackson .databind .util .internal .PrivateMaxEntriesMap ;
5
4
6
5
/**
7
6
* Helper for simple bounded maps used for reusing lookup values.
10
9
* on assumption that all use cases are for caching where persistence
11
10
* does not make sense. The only thing serialized is the cache size of Map.
12
11
*<p>
13
- * NOTE: since version 2.4.2, this is <b>NOT</b> an LRU-based at all; reason
14
- * being that it is not possible to use JDK components that do LRU _AND_ perform
15
- * well wrt synchronization on multi-core systems. So we choose efficient synchronization
16
- * over potentially more efficient handling of entries.
12
+ * NOTE: since Jackson 2.14, the implementation evicts the least recently used
13
+ * entry when max size is reached.
17
14
*<p>
18
- * And yes, there are efficient LRU implementations such as
19
- * <a href="https://code.google.com/p/concurrentlinkedhashmap/">concurrentlinkedhashmap</a>;
20
- * but at this point we really try to keep external deps to minimum.
21
- * Plan from Jackson 2.12 is to focus more on pluggability as {@link LookupCache} and
22
- * let users, frameworks, provide their own cache implementations.
15
+ * Since Jackson 2.12, there has been pluggable {@link LookupCache} interface which
16
+ * allows users, frameworks, provide their own cache implementations.
23
17
*/
24
18
public class LRUMap <K ,V >
25
19
implements LookupCache <K ,V >, // since 2.12
26
20
java .io .Serializable
27
21
{
28
- private static final long serialVersionUID = 1L ;
22
+ private static final long serialVersionUID = 2L ;
29
23
30
- protected final transient int _maxEntries ;
24
+ protected final int _initialEntries ;
25
+ protected final int _maxEntries ;
26
+ protected final transient PrivateMaxEntriesMap <K ,V > _map ;
31
27
32
- protected final transient ConcurrentHashMap <K ,V > _map ;
33
-
34
28
public LRUMap (int initialEntries , int maxEntries )
35
29
{
36
- // We'll use concurrency level of 4, seems reasonable
37
- _map = new ConcurrentHashMap <K ,V >(initialEntries , 0.8f , 4 );
30
+ _initialEntries = initialEntries ;
38
31
_maxEntries = maxEntries ;
32
+ // We'll use concurrency level of 4, seems reasonable
33
+ _map = new PrivateMaxEntriesMap .Builder <K , V >()
34
+ .initialCapacity (initialEntries )
35
+ .maximumCapacity (maxEntries )
36
+ .concurrencyLevel (4 )
37
+ .build ();
39
38
}
40
39
41
40
@ Override
42
41
public V put (K key , V value ) {
43
- if (_map .size () >= _maxEntries ) {
44
- // double-locking, yes, but safe here; trying to avoid "clear storms"
45
- synchronized (this ) {
46
- if (_map .size () >= _maxEntries ) {
47
- clear ();
48
- }
49
- }
50
- }
51
42
return _map .put (key , value );
52
43
}
53
44
@@ -56,21 +47,12 @@ public V put(K key, V value) {
56
47
*/
57
48
@ Override
58
49
public V putIfAbsent (K key , V value ) {
59
- // not 100% optimal semantically, but better from correctness (never exceeds
60
- // defined maximum) and close enough all in all:
61
- if (_map .size () >= _maxEntries ) {
62
- synchronized (this ) {
63
- if (_map .size () >= _maxEntries ) {
64
- clear ();
65
- }
66
- }
67
- }
68
50
return _map .putIfAbsent (key , value );
69
51
}
70
52
71
53
// NOTE: key is of type Object only to retain binary backwards-compatibility
72
54
@ Override
73
- public V get (Object key ) { return _map .get (key ); }
55
+ public V get (Object key ) { return _map .get (key ); }
74
56
75
57
@ Override
76
58
public void clear () { _map .clear (); }
@@ -84,23 +66,7 @@ public V putIfAbsent(K key, V value) {
84
66
/**********************************************************
85
67
*/
86
68
87
- /**
88
- * Ugly hack, to work through the requirement that _value is indeed final,
89
- * and that JDK serialization won't call ctor(s) if Serializable is implemented.
90
- *
91
- * @since 2.1
92
- */
93
- protected transient int _jdkSerializeMaxEntries ;
94
-
95
- private void readObject (ObjectInputStream in ) throws IOException {
96
- _jdkSerializeMaxEntries = in .readInt ();
97
- }
98
-
99
- private void writeObject (ObjectOutputStream out ) throws IOException {
100
- out .writeInt (_jdkSerializeMaxEntries );
101
- }
102
-
103
69
protected Object readResolve () {
104
- return new LRUMap <Object , Object >( _jdkSerializeMaxEntries , _jdkSerializeMaxEntries );
70
+ return new LRUMap <K , V >( _initialEntries , _maxEntries );
105
71
}
106
72
}
0 commit comments