11package datadog .trace .api .cache ;
22
33import datadog .trace .bootstrap .instrumentation .api .UTF8BytesString ;
4- import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
5- import java .util .concurrent .atomic .AtomicReferenceArray ;
64import java .util .function .IntFunction ;
75
86/** Sparse cache of values associated with a small integer */
@@ -25,11 +23,11 @@ public final class RadixTreeCache<T> {
2523 private final int shift ;
2624 private final int mask ;
2725
28- private final AtomicReferenceArray < Object []> tree ;
26+ private final Object [][] tree ;
2927 private final IntFunction <T > mapper ;
3028
3129 public RadixTreeCache (int level1 , int level2 , IntFunction <T > mapper , int ... commonValues ) {
32- this .tree = new AtomicReferenceArray <>( level1 ) ;
30+ this .tree = new Object [ level1 ][] ;
3331 this .mapper = mapper ;
3432 this .level1 = level1 ;
3533 this .level2 = level2 ;
@@ -50,31 +48,15 @@ public T get(int primitive) {
5048 }
5149
5250 @ SuppressWarnings ("unchecked" )
53- @ SuppressFBWarnings ("DCN" ) // only interested in catching NullPointerException (see note below)
5451 private T computeIfAbsent (int prefix , int primitive ) {
55- Object [] page = tree .get (prefix );
56- if (null == page ) {
57- try {
58- page = new Object [level2 ];
59- if (!tree .compareAndSet (prefix , null , page )) {
60- page = tree .get (prefix );
61- }
62- } catch (NullPointerException e ) {
63- // Intermittent NPE observed in JDK code on Semeru 11.0.29: java.lang.NullPointerException:
64- // at j.l.i.ArrayVarHandle$...Operations$OpObject.computeOffset(ArrayVarHandle.java:142)
65- // at j.l.i.ArrayVarHandle$...Operations$OpObject.compareAndSet(ArrayVarHandle.java:201)
66- // at j.u.c.atomic.AtomicReferenceArray.compareAndSet(AtomicReferenceArray.java:152)
67- // at datadog.trace.api.cache.RadixTreeCache.computeIfAbsent(RadixTreeCache.java:59)
68- // Location indicates JDK's VarHandle used to access the backing array has returned null
69- // To mitigate this rare JDK bug we still map the primitive but skip caching the result
70- return mapper .apply (primitive );
71- }
52+ Object [] page = tree [prefix ];
53+ if (page == null ) {
54+ page = tree [prefix ] = new Object [level2 ]; // tolerate race to cache sub-array
7255 }
73- // it's safe to race here
7456 int suffix = primitive & mask ;
7557 Object cached = page [suffix ];
7658 if (cached == null ) {
77- cached = page [suffix ] = mapper .apply (primitive );
59+ cached = page [suffix ] = mapper .apply (primitive ); // tolerate race to cache value
7860 }
7961 return (T ) cached ;
8062 }
0 commit comments