1313import java .util .Collections ;
1414import java .util .List ;
1515import java .util .function .BiFunction ;
16+ import javax .annotation .Nullable ;
1617
1718/** Base for fixed-size reservoir sampling of Exemplars. */
1819abstract class FixedSizeExemplarReservoir <T extends ExemplarData > implements ExemplarReservoir <T > {
1920
20- private final ReservoirCell [] storage ;
21+ @ Nullable private ReservoirCell [] storage ;
2122 private final ReservoirCellSelector reservoirCellSelector ;
2223 private final BiFunction <ReservoirCell , Attributes , T > mapAndResetCell ;
24+ private final int size ;
25+ private final Clock clock ;
2326 private volatile boolean hasMeasurements = false ;
2427
2528 /** Instantiates an exemplar reservoir of fixed size. */
@@ -28,16 +31,18 @@ abstract class FixedSizeExemplarReservoir<T extends ExemplarData> implements Exe
2831 int size ,
2932 ReservoirCellSelector reservoirCellSelector ,
3033 BiFunction <ReservoirCell , Attributes , T > mapAndResetCell ) {
31- this .storage = new ReservoirCell [size ];
32- for (int i = 0 ; i < size ; ++i ) {
33- this .storage [i ] = new ReservoirCell (clock );
34- }
34+ this .storage = null ; // lazily initialize to avoid allocations
35+ this .size = size ;
36+ this .clock = clock ;
3537 this .reservoirCellSelector = reservoirCellSelector ;
3638 this .mapAndResetCell = mapAndResetCell ;
3739 }
3840
3941 @ Override
4042 public void offerLongMeasurement (long value , Attributes attributes , Context context ) {
43+ if (storage == null ) {
44+ storage = initStorage ();
45+ }
4146 int bucket = reservoirCellSelector .reservoirCellIndexFor (storage , value , attributes , context );
4247 if (bucket != -1 ) {
4348 this .storage [bucket ].recordLongMeasurement (value , attributes , context );
@@ -47,16 +52,27 @@ public void offerLongMeasurement(long value, Attributes attributes, Context cont
4752
4853 @ Override
4954 public void offerDoubleMeasurement (double value , Attributes attributes , Context context ) {
55+ if (storage == null ) {
56+ storage = initStorage ();
57+ }
5058 int bucket = reservoirCellSelector .reservoirCellIndexFor (storage , value , attributes , context );
5159 if (bucket != -1 ) {
5260 this .storage [bucket ].recordDoubleMeasurement (value , attributes , context );
5361 this .hasMeasurements = true ;
5462 }
5563 }
5664
65+ private ReservoirCell [] initStorage () {
66+ ReservoirCell [] storage = new ReservoirCell [this .size ];
67+ for (int i = 0 ; i < size ; ++i ) {
68+ storage [i ] = new ReservoirCell (this .clock );
69+ }
70+ return storage ;
71+ }
72+
5773 @ Override
5874 public List <T > collectAndReset (Attributes pointAttributes ) {
59- if (!hasMeasurements ) {
75+ if (!hasMeasurements || storage == null ) {
6076 return Collections .emptyList ();
6177 }
6278 // Note: we are collecting exemplars from buckets piecemeal, but we
0 commit comments