1717
1818package org .apache .hadoop .ozone .container .diskbalancer ;
1919
20- import com .google .common .base .Preconditions ;
21- import com .google .common .collect .ImmutableList ;
20+ import static org .apache .ratis .util .Preconditions .assertInstanceOf ;
21+ import static org .apache .ratis .util .Preconditions .assertTrue ;
22+
2223import java .util .List ;
2324import java .util .Map ;
25+ import java .util .Objects ;
26+ import java .util .stream .Collectors ;
2427import org .apache .hadoop .hdds .fs .SpaceUsageSource ;
25- import org .apache .hadoop .ozone .container .common .utils .StorageVolumeUtil ;
2628import org .apache .hadoop .ozone .container .common .volume .HddsVolume ;
2729import org .apache .hadoop .ozone .container .common .volume .MutableVolumeSet ;
30+ import org .apache .hadoop .ozone .container .common .volume .StorageVolume ;
31+ import org .apache .hadoop .ozone .container .common .volume .VolumeUsage ;
2832import org .slf4j .Logger ;
2933import org .slf4j .LoggerFactory ;
3034
@@ -47,51 +51,42 @@ private DiskBalancerVolumeCalculation() {
4751
4852 /**
4953 * Get an immutable snapshot of volumes from a MutableVolumeSet.
50- *
54+ *
5155 * @param volumeSet The MutableVolumeSet to create a snapshot from
52- * @return Immutable list of HddsVolume objects
56+ * @return a list of volumes and usages
5357 */
54- public static ImmutableList < HddsVolume > getImmutableVolumeSet (MutableVolumeSet volumeSet ) {
55- // Create an immutable copy of the volume list at this point in time
56- List < HddsVolume > volumes = StorageVolumeUtil . getHddsVolumesList ( volumeSet . getVolumesList ());
57- return ImmutableList . copyOf ( volumes );
58+ public static List < VolumeFixedUsage > getVolumeUsages (MutableVolumeSet volumeSet , Map < HddsVolume , Long > deltas ) {
59+ return volumeSet . getVolumesList (). stream ()
60+ . map ( v -> newVolumeFixedUsage ( v , deltas ))
61+ . collect ( Collectors . toList () );
5862 }
5963
6064 /**
6165 * Get ideal usage from an immutable list of volumes.
6266 *
6367 * @param volumes Immutable list of volumes
64- * @param deltaMap A map that tracks the total bytes which will be freed
6568 * from each source volume during container moves
6669 * @return Ideal usage as a ratio (used space / total capacity)
6770 * @throws IllegalArgumentException if total capacity is zero
6871 */
69- public static double getIdealUsage (ImmutableList <HddsVolume > volumes ,
70- Map <HddsVolume , Long > deltaMap ) {
72+ public static double getIdealUsage (List <VolumeFixedUsage > volumes ) {
7173 long totalCapacity = 0L , totalEffectiveUsed = 0L ;
7274
73- for (HddsVolume volume : volumes ) {
74- SpaceUsageSource usage = volume .getCurrentUsage ();
75- totalCapacity += usage .getCapacity ();
76- long currentUsed = usage .getCapacity () - usage .getAvailable ();
77- long delta = (deltaMap != null ) ? deltaMap .getOrDefault (volume , 0L ) : 0L ;
78- long committed = volume .getCommittedBytes ();
79- totalEffectiveUsed += (currentUsed + delta + committed );
75+ for (VolumeFixedUsage volumeUsage : volumes ) {
76+ totalCapacity += volumeUsage .getUsage ().getCapacity ();
77+ totalEffectiveUsed += volumeUsage .getEffectiveUsed ();
8078 }
8179
82- Preconditions .checkArgument (totalCapacity != 0 );
8380 return ((double ) (totalEffectiveUsed )) / totalCapacity ;
8481 }
8582
8683 /**
8784 * Calculate VolumeDataDensity.
8885 *
8986 * @param volumeSet The MutableVolumeSet containing all volumes
90- * @param deltaMap Map of volume to delta sizes (ongoing operations), can be null
9187 * @return VolumeDataDensity sum across all volumes
9288 */
93- public static double calculateVolumeDataDensity (ImmutableList <HddsVolume > volumeSet ,
94- Map <HddsVolume , Long > deltaMap ) {
89+ public static double calculateVolumeDataDensity (List <VolumeFixedUsage > volumeSet ) {
9590 if (volumeSet == null ) {
9691 LOG .warn ("VolumeSet is null, returning 0.0 for VolumeDataDensity" );
9792 return 0.0 ;
@@ -104,18 +99,13 @@ public static double calculateVolumeDataDensity(ImmutableList<HddsVolume> volume
10499 }
105100
106101 // Calculate ideal usage using the same immutable volume snapshot
107- double idealUsage = getIdealUsage (volumeSet , deltaMap );
102+ final double idealUsage = getIdealUsage (volumeSet );
108103 double volumeDensitySum = 0.0 ;
109104
110105 // Calculate density for each volume using the same snapshot
111- for (HddsVolume volume : volumeSet ) {
112- SpaceUsageSource usage = volume .getCurrentUsage ();
113- Preconditions .checkArgument (usage .getCapacity () != 0 );
114-
115- long deltaSize = (deltaMap != null ) ? deltaMap .getOrDefault (volume , 0L ) : 0L ;
116- double currentUsage = (double )((usage .getCapacity () - usage .getAvailable ())
117- + deltaSize + volume .getCommittedBytes ()) / usage .getCapacity ();
118-
106+ for (VolumeFixedUsage volumeUsage : volumeSet ) {
107+ final double currentUsage = volumeUsage .getUtilization ();
108+
119109 // Calculate density as absolute difference from ideal usage
120110 double volumeDensity = Math .abs (currentUsage - idealUsage );
121111 volumeDensitySum += volumeDensity ;
@@ -126,4 +116,56 @@ public static double calculateVolumeDataDensity(ImmutableList<HddsVolume> volume
126116 return -1.0 ;
127117 }
128118 }
119+
120+ public static double computeUtilization (SpaceUsageSource .Fixed usage , long committed , long required ) {
121+ final long capacity = usage .getCapacity ();
122+ assertTrue (capacity > 0 , () -> "capacity = " + capacity + " <= 0" );
123+ return computeEffectiveUsage (usage , committed , required ) / (double ) capacity ;
124+ }
125+
126+ private static long computeEffectiveUsage (SpaceUsageSource .Fixed usage , long committed , long required ) {
127+ return usage .getCapacity () - usage .getAvailable () + committed + required ;
128+ }
129+
130+ public static VolumeFixedUsage newVolumeFixedUsage (StorageVolume volume , Map <HddsVolume , Long > deltaMap ) {
131+ final HddsVolume v = assertInstanceOf (volume , HddsVolume .class );
132+ final long delta = deltaMap == null ? 0 : deltaMap .getOrDefault (v , 0L );
133+ return new VolumeFixedUsage (v , delta );
134+ }
135+
136+ /** {@link HddsVolume} with a {@link SpaceUsageSource.Fixed} usage. */
137+ public static final class VolumeFixedUsage {
138+ private final HddsVolume volume ;
139+ private final SpaceUsageSource .Fixed usage ;
140+ private final long effectiveUsed ;
141+ private final Double utilization ;
142+
143+ private VolumeFixedUsage (HddsVolume volume , long delta ) {
144+ this .volume = volume ;
145+ this .usage = volume .getCurrentUsage ();
146+ this .effectiveUsed = computeEffectiveUsage (usage , volume .getCommittedBytes (), delta );
147+ this .utilization = usage .getCapacity () > 0 ? computeUtilization (usage , volume .getCommittedBytes (), delta ) : null ;
148+ }
149+
150+ public HddsVolume getVolume () {
151+ return volume ;
152+ }
153+
154+ public SpaceUsageSource .Fixed getUsage () {
155+ return usage ;
156+ }
157+
158+ public long getEffectiveUsed () {
159+ return effectiveUsed ;
160+ }
161+
162+ public double getUtilization () {
163+ return Objects .requireNonNull (utilization , "utilization == null" );
164+ }
165+
166+ public long computeUsableSpace () {
167+ final long spared = volume .getFreeSpaceToSpare (usage .getCapacity ());
168+ return VolumeUsage .getUsableSpace (usage .getAvailable (), volume .getCommittedBytes (), spared );
169+ }
170+ }
129171}
0 commit comments