diff --git a/src/SnapDB/Snap/Services/Writer/ArchiveInitializer.cs b/src/SnapDB/Snap/Services/Writer/ArchiveInitializer.cs index 8d33fe6d..e7b8ebc3 100644 --- a/src/SnapDB/Snap/Services/Writer/ArchiveInitializer.cs +++ b/src/SnapDB/Snap/Services/Writer/ArchiveInitializer.cs @@ -211,14 +211,134 @@ private string GetPathWithEnoughSpace(long estimatedSize) long remainingSpace = Settings.DesiredRemainingSpace; - foreach (string path in Settings.WritePath) + if (Settings.BalancingMethod == BalancingMethod.FillToDesired) { - FilePath.GetAvailableFreeSpace(path, out long freeSpace, out _); + foreach (string path in Settings.WritePath) + { + FilePath.GetAvailableFreeSpace(path, out long freeSpace, out _); + + //If there is space, fill it. + if (freeSpace - estimatedSize > remainingSpace) + return path; + + } + } + + if (Settings.BalancingMethod == BalancingMethod.FillSmallestAvailable) + { + long current = 0; + string smallest = null; + + foreach (string path in Settings.WritePath) + { + FilePath.GetAvailableFreeSpace(path, out long freeSpace, out _); + + // Checks to ensure that this path has enough available space to write to + if (freeSpace - estimatedSize < remainingSpace) + continue; + + // If the path we are checking has less free space than the previous path, that becomes the path with the least available space. + if (freeSpace < current) + { + smallest = path; + current = freeSpace; + } + } + + if (!string.IsNullOrEmpty(smallest)) + return smallest; + } + + if (Settings.BalancingMethod == BalancingMethod.FillLargestAvailable) + { + long current = 0; + string largest = null; + + foreach (string path in Settings.WritePath) + { + FilePath.GetAvailableFreeSpace(path, out long freeSpace, out _); + + if (freeSpace - estimatedSize < remainingSpace) + continue; + + // If the path we are checking has more free space than the previous path, that becomes the path with the most available space. + if (freeSpace > current) + { + largest = path; + current = freeSpace; + } + } + + if(!string.IsNullOrEmpty(largest)) + return largest; - if (freeSpace - estimatedSize > remainingSpace) - return path; } + if (Settings.BalancingMethod == BalancingMethod.FillLargestTotal) + { + long current = 0; + + string largestTotal = null; + + foreach (string path in Settings.WritePath) + { + FilePath.GetAvailableFreeSpace(path, out long freeSpace, out long totalSize); + + if (freeSpace - estimatedSize < remainingSpace) + continue; + + // If the path we are looking at has a greater total size than the previous one, it becomes the largestTotal. + if (totalSize > current) + { + largestTotal = path; + current = freeSpace; + } + + } + + if (!string.IsNullOrEmpty(largestTotal)) + return largestTotal; + } + + if (Settings.BalancingMethod == BalancingMethod.FillToMatchingPercentage) + { + // what percentage of the current path is left free + long currentRemainingPercentage; + // the occupancy percentage of the most empty space + long fullestPercentage = 0; + // the location that needs to be filled, i.e. the location with the emptiestPercentage + string toFill = null; + + foreach (string path in Settings.WritePath) + { + FilePath.GetAvailableFreeSpace(path, out long freeSpace, out long totalSize); + + if (freeSpace - estimatedSize < remainingSpace) + continue; + + currentRemainingPercentage = freeSpace / totalSize; + + // Compares the percentage that is free to the fullestPercentage + if (currentRemainingPercentage == fullestPercentage) + continue; + + // If the remaining percentage of available space for this path is greater than the remaining percentage of the + // previous one, this occupancy percentage becomes the standard for the rest to be compared to. + if (currentRemainingPercentage > fullestPercentage) + fullestPercentage = currentRemainingPercentage; + + // If the remaining percentage of available space for this path is smaller than the remaining percentage of the + // fullest path, this path must be filled to that standard. + if (currentRemainingPercentage < fullestPercentage) + toFill = path; + } + + if (!string.IsNullOrEmpty(toFill)) + return toFill; + } + + //for pct, calculate percentage as freespace/totalspace then pick the largest to fill to a point + throw new InvalidOperationException("Out of free space"); } diff --git a/src/SnapDB/Snap/Services/Writer/ArchiveInitializerSettings.cs b/src/SnapDB/Snap/Services/Writer/ArchiveInitializerSettings.cs index ccb3b826..7aac922e 100644 --- a/src/SnapDB/Snap/Services/Writer/ArchiveInitializerSettings.cs +++ b/src/SnapDB/Snap/Services/Writer/ArchiveInitializerSettings.cs @@ -31,6 +31,30 @@ namespace SnapDB.Snap.Services.Writer; +public enum BalancingMethod +{ + /// + /// Fills the path to meet the desired free space, prioritizing paths with the most available space + /// + FillToDesired, + /// + /// Fills the path with the least available space + /// + FillSmallestAvailable, + /// + /// Fills the path with the most available space + /// + FillLargestAvailable, + /// + /// Fills the path with the most space, available or not, as long as there is room + /// + FillLargestTotal, + /// + /// Fills each path to the same amount across the board + /// + FillToMatchingPercentage +} + /// /// Settings for . /// @@ -39,6 +63,7 @@ public class ArchiveInitializerSettings : SettingsBase + /// The method used to balance file share load. + /// + public BalancingMethod BalancingMethod + { + get => m_balancingMethod; + set + { + TestForEditable(); + + m_balancingMethod = value; + } + } + /// /// Gets the method that the directory structure will follow when writing a new file. /// @@ -316,6 +355,7 @@ private void Initialize() m_fileExtension = ".d2i"; m_desiredRemainingSpace = 5 * 1024 * 1024 * 1024L; //5GB m_encodingMethod = EncodingDefinition.FixedSizeCombinedEncoding; + m_balancingMethod = BalancingMethod.FillToDesired; WritePath = new ImmutableList(x => { PathHelpers.ValidatePathName(x);