16
16
import java .io .IOException ;
17
17
import java .io .PrintWriter ;
18
18
import java .io .StringWriter ;
19
+ import java .lang .reflect .RecordComponent ;
19
20
import java .nio .ByteBuffer ;
20
21
import java .time .Instant ;
21
22
import java .util .Arrays ;
23
+ import java .util .HashMap ;
22
24
import java .util .List ;
25
+ import java .util .Map ;
23
26
import java .util .Objects ;
24
27
import java .util .Set ;
25
28
import java .util .concurrent .ConcurrentHashMap ;
29
32
import java .util .concurrent .atomic .AtomicBoolean ;
30
33
import java .util .concurrent .atomic .LongAdder ;
31
34
import java .util .function .IntUnaryOperator ;
35
+ import java .util .function .ToLongFunction ;
32
36
import java .util .stream .Collectors ;
33
37
34
38
import org .eclipse .jetty .io .internal .CompoundPool ;
@@ -333,7 +337,7 @@ private void checkMaxMemory(RetainedBucket bucket, boolean direct)
333
337
return ;
334
338
try
335
339
{
336
- long memory = getMemory (direct );
340
+ long memory = getTotalMemory (direct );
337
341
long excess = memory - max ;
338
342
if (excess > 0 )
339
343
{
@@ -418,34 +422,81 @@ private long getAvailableByteBufferCount(boolean direct)
418
422
return Arrays .stream (buckets ).mapToLong (bucket -> bucket .getPool ().getIdleCount ()).sum ();
419
423
}
420
424
421
- @ ManagedAttribute ("The bytes retained by direct ByteBuffers" )
425
+ @ ManagedAttribute ("The total bytes retained by direct ByteBuffers" )
422
426
public long getDirectMemory ()
423
427
{
424
- return getMemory (true );
428
+ return getTotalMemory (true );
425
429
}
426
430
427
- @ ManagedAttribute ("The bytes retained by heap ByteBuffers" )
431
+ @ ManagedAttribute ("The total bytes retained by heap ByteBuffers" )
428
432
public long getHeapMemory ()
429
433
{
430
- return getMemory (false );
434
+ return getTotalMemory (false );
431
435
}
432
436
433
- private long getMemory (boolean direct )
437
+ private long getTotalMemory (boolean direct )
438
+ {
439
+ return getMemory (direct , bucket -> bucket .getPool ().size ());
440
+ }
441
+
442
+ private long getMemory (boolean direct , ToLongFunction <RetainedBucket > count )
434
443
{
435
444
long size = 0 ;
436
445
for (RetainedBucket bucket : direct ? _direct : _indirect )
437
- size += ( long ) bucket . getPool (). getIdleCount ( ) * bucket .getCapacity ();
446
+ size += count . applyAsLong ( bucket ) * bucket .getCapacity ();
438
447
return size ;
439
448
}
440
449
450
+ @ ManagedAttribute ("The available bytes retained by direct ByteBuffers" )
441
451
public long getAvailableDirectMemory ()
442
452
{
443
- return getDirectMemory ( );
453
+ return getAvailableMemory ( true );
444
454
}
445
455
456
+ @ ManagedAttribute ("The available bytes retained by heap ByteBuffers" )
446
457
public long getAvailableHeapMemory ()
447
458
{
448
- return getHeapMemory ();
459
+ return getAvailableMemory (false );
460
+ }
461
+
462
+ private long getAvailableMemory (boolean direct )
463
+ {
464
+ return getMemory (direct , bucket -> bucket .getPool ().getIdleCount ());
465
+ }
466
+
467
+ @ ManagedAttribute ("The heap buckets statistics" )
468
+ public List <Map <String , Object >> getHeapBucketsStatistics ()
469
+ {
470
+ return getBucketsStatistics (false );
471
+ }
472
+
473
+ @ ManagedAttribute ("The direct buckets statistics" )
474
+ public List <Map <String , Object >> getDirectBucketsStatistics ()
475
+ {
476
+ return getBucketsStatistics (true );
477
+ }
478
+
479
+ private List <Map <String , Object >> getBucketsStatistics (boolean direct )
480
+ {
481
+ RetainedBucket [] buckets = direct ? _direct : _indirect ;
482
+ return Arrays .stream (buckets ).map (b -> b .getStatistics ().toMap ()).toList ();
483
+ }
484
+
485
+ @ ManagedAttribute ("The acquires for direct non-pooled bucket capacities" )
486
+ public Map <Integer , Long > getNoBucketDirectAcquires ()
487
+ {
488
+ return getNoBucketAcquires (true );
489
+ }
490
+
491
+ @ ManagedAttribute ("The acquires for heap non-pooled bucket capacities" )
492
+ public Map <Integer , Long > getNoBucketHeapAcquires ()
493
+ {
494
+ return getNoBucketAcquires (false );
495
+ }
496
+
497
+ private Map <Integer , Long > getNoBucketAcquires (boolean direct )
498
+ {
499
+ return new HashMap <>(direct ? _noBucketDirectAcquires : _noBucketIndirectAcquires );
449
500
}
450
501
451
502
@ ManagedOperation (value = "Clears this ByteBufferPool" , impact = "ACTION" )
@@ -475,7 +526,7 @@ public void dump(Appendable out, String indent) throws IOException
475
526
DumpableCollection .fromArray ("direct" , _direct ),
476
527
new DumpableMap ("direct non-pooled acquisitions" , _noBucketDirectAcquires ),
477
528
DumpableCollection .fromArray ("indirect" , _indirect ),
478
- new DumpableMap ("indirect non-pooled acquisitions" , _noBucketIndirectAcquires )
529
+ new DumpableMap ("heap non-pooled acquisitions" , _noBucketIndirectAcquires )
479
530
);
480
531
}
481
532
@@ -576,6 +627,17 @@ private int evict()
576
627
return getCapacity ();
577
628
}
578
629
630
+ private Statistics getStatistics ()
631
+ {
632
+ List <Pool .Entry <RetainableByteBuffer >> entries = getPool ().stream ().toList ();
633
+ int inUse = (int )entries .stream ().filter (Pool .Entry ::isInUse ).count ();
634
+ long pooled = _pooled .longValue ();
635
+ long acquires = _acquires .longValue ();
636
+ float hitRatio = acquires == 0 ? Float .NaN : pooled * 100F / acquires ;
637
+ return new Statistics (getCapacity (), inUse , entries .size (), pooled , acquires , _releases .longValue (),
638
+ hitRatio , _nonPooled .longValue (), _evicts .longValue (), _removes .longValue ());
639
+ }
640
+
579
641
public void clear ()
580
642
{
581
643
_acquires .reset ();
@@ -590,31 +652,45 @@ public void clear()
590
652
@ Override
591
653
public String toString ()
592
654
{
593
- int entries = 0 ;
594
- int inUse = 0 ;
595
- for (Pool .Entry <RetainableByteBuffer > entry : getPool ().stream ().toList ())
655
+ return String .format ("%s[%s]" , super .toString (), getStatistics ());
656
+ }
657
+
658
+ private record Statistics (int capacity , int inUseEntries , int totalEntries , long pooled , long acquires ,
659
+ long releases , float hitRatio , long nonPooled , long evicts , long removes )
660
+ {
661
+ private Map <String , Object > toMap ()
596
662
{
597
- entries ++;
598
- if (entry .isInUse ())
599
- inUse ++;
663
+ try
664
+ {
665
+ Map <String , Object > statistics = new HashMap <>();
666
+ for (RecordComponent c : getClass ().getRecordComponents ())
667
+ {
668
+ statistics .put (c .getName (), c .getAccessor ().invoke (this ));
669
+ }
670
+ return statistics ;
671
+ }
672
+ catch (Throwable x )
673
+ {
674
+ return Map .of ();
675
+ }
600
676
}
601
677
602
- long pooled = _pooled . longValue ();
603
- long acquires = _acquires . longValue ();
604
- float hitRatio = acquires == 0 ? Float . NaN : pooled * 100F / acquires ;
605
- return String . format ( "%s{ capacity=%d,in-use=%d/%d,pooled/acquires=%d/%d(%.3f%%),non-pooled/evicts/removes/releases =%d/%d/%d/%d}" ,
606
- super . toString () ,
607
- getCapacity () ,
608
- inUse ,
609
- entries ,
610
- pooled ,
611
- acquires ,
612
- hitRatio ,
613
- _nonPooled . longValue () ,
614
- _evicts . longValue () ,
615
- _removes . longValue (),
616
- _releases . longValue ()
617
- );
678
+ @ Override
679
+ public String toString ()
680
+ {
681
+ return " capacity=%d,in-use=%d/%d,pooled/acquires/releases =%d/%d/%d (%.3f%%),non-pooled/evicts/removes=%d/%d/%d" . formatted (
682
+ capacity ,
683
+ inUseEntries ,
684
+ totalEntries ,
685
+ pooled ,
686
+ acquires ,
687
+ releases ,
688
+ hitRatio ,
689
+ nonPooled ,
690
+ evicts ,
691
+ removes
692
+ );
693
+ }
618
694
}
619
695
620
696
private static class BucketCompoundPool extends CompoundPool <RetainableByteBuffer >
0 commit comments