public static PartitionKeyHashRanges Create(IEnumerable <PartitionKeyHashRange> partitionKeyHashRanges) { CreateOutcome createStatus = PartitionKeyHashRanges.TryCreate( partitionKeyHashRanges, out PartitionKeyHashRanges partitionedSortedEffectiveRanges); switch (createStatus) { case CreateOutcome.DuplicatePartitionKeyRange: throw new ArgumentException($"{nameof(partitionKeyHashRanges)} must not have duplicate values."); case CreateOutcome.EmptyPartitionKeyRange: throw new ArgumentException($"{nameof(partitionKeyHashRanges)} must not have an empty range."); case CreateOutcome.NoPartitionKeyRanges: throw new ArgumentException($"{nameof(partitionKeyHashRanges)} must not be empty."); case CreateOutcome.NullPartitionKeyRanges: throw new ArgumentNullException(nameof(partitionKeyHashRanges)); case CreateOutcome.RangesAreNotContiguous: throw new ArgumentException($"{nameof(partitionKeyHashRanges)} must have contiguous ranges."); case CreateOutcome.RangesOverlap: throw new ArgumentException($"{nameof(partitionKeyHashRanges)} must not overlapping ranges."); case CreateOutcome.Success: return(partitionedSortedEffectiveRanges); default: throw new ArgumentOutOfRangeException($"Unknown {nameof(CreateOutcome)}: {createStatus}."); } }
public static PartitionKeyHashRange MergeRanges(PartitionKeyHashRanges partitionedSortedEffectiveRanges) { if (partitionedSortedEffectiveRanges == null) { throw new ArgumentNullException(nameof(partitionedSortedEffectiveRanges)); } return(new PartitionKeyHashRange( startInclusive: partitionedSortedEffectiveRanges.First().StartInclusive, endExclusive: partitionedSortedEffectiveRanges.Last().EndExclusive)); }
public static SplitOutcome TrySplitRange(PartitionKeyHashRange partitionKeyHashRange, int rangeCount, out PartitionKeyHashRanges splitRanges) { if (rangeCount < 1) { splitRanges = default; return(SplitOutcome.NumRangesNeedsToBeGreaterThanZero); } UInt128 actualEnd = partitionKeyHashRange.EndExclusive.HasValue ? partitionKeyHashRange.EndExclusive.Value.Value : UInt128.MaxValue; UInt128 actualStart = partitionKeyHashRange.StartInclusive.HasValue ? partitionKeyHashRange.StartInclusive.Value.Value : UInt128.MinValue; UInt128 rangeLength = actualEnd - actualStart; if (rangeLength < rangeCount) { splitRanges = default; return(SplitOutcome.RangeNotWideEnough); } if (rangeCount == 1) { // Just return the range as is: splitRanges = PartitionKeyHashRanges.Create(new PartitionKeyHashRange[] { partitionKeyHashRange }); return(SplitOutcome.Success); } List <PartitionKeyHashRange> childRanges = new List <PartitionKeyHashRange>(); UInt128 childRangeLength = rangeLength / rangeCount; // First range should start at the user supplied range (since the input might have an open range and we don't want to return 0) { PartitionKeyHash?start = partitionKeyHashRange.StartInclusive; PartitionKeyHash end = new PartitionKeyHash(actualStart + childRangeLength); childRanges.Add(new PartitionKeyHashRange(start, end)); } for (int i = 1; i < rangeCount - 1; i++) { PartitionKeyHash start = new PartitionKeyHash(actualStart + (childRangeLength * i)); PartitionKeyHash end = new PartitionKeyHash(start.Value + childRangeLength); childRanges.Add(new PartitionKeyHashRange(start, end)); } // Last range will have remaining EPKs, since the range might not be divisible. { PartitionKeyHash start = new PartitionKeyHash(actualStart + (childRangeLength * (rangeCount - 1))); PartitionKeyHash?end = partitionKeyHashRange.EndExclusive; childRanges.Add(new PartitionKeyHashRange(start, end)); } splitRanges = PartitionKeyHashRanges.Create(childRanges); return(SplitOutcome.Success); }
public static TryCatch <PartitionKeyHashRanges> Create(IEnumerable <PartitionKeyHashRange> partitionKeyHashRanges) { CreateOutcome createStatus = PartitionKeyHashRanges.TryCreate( partitionKeyHashRanges, out PartitionKeyHashRanges partitionedSortedEffectiveRanges); return(createStatus switch { CreateOutcome.DuplicatePartitionKeyRange => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentException($"{nameof(partitionKeyHashRanges)} must not have duplicate values.")), CreateOutcome.EmptyPartitionKeyRange => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentException($"{nameof(partitionKeyHashRanges)} must not have an empty range.")), CreateOutcome.NoPartitionKeyRanges => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentException($"{nameof(partitionKeyHashRanges)} must not be empty.")), CreateOutcome.NullPartitionKeyRanges => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentNullException(nameof(partitionKeyHashRanges))), CreateOutcome.RangesAreNotContiguous => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentException($"{nameof(partitionKeyHashRanges)} must have contiguous ranges.")), CreateOutcome.RangesOverlap => TryCatch <PartitionKeyHashRanges> .FromException( new ArgumentException($"{nameof(partitionKeyHashRanges)} must not overlapping ranges.")), CreateOutcome.Success => TryCatch <PartitionKeyHashRanges> .FromResult(partitionedSortedEffectiveRanges), _ => throw new ArgumentOutOfRangeException($"Unknown {nameof(CreateOutcome)}: {createStatus}."), });
public static CreateOutcome TryCreate( IEnumerable <PartitionKeyHashRange> partitionKeyHashRanges, out PartitionKeyHashRanges partitionedSortedEffectiveRanges) { if (partitionKeyHashRanges == null) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.NullPartitionKeyRanges); } if (partitionKeyHashRanges.Count() == 0) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.NoPartitionKeyRanges); } SortedSet <PartitionKeyHashRange> sortedSet = new SortedSet <PartitionKeyHashRange>(); foreach (PartitionKeyHashRange partitionKeyHashRange in partitionKeyHashRanges) { if (partitionKeyHashRange.StartInclusive.Equals(partitionKeyHashRange.EndExclusive)) { if (partitionKeyHashRange.StartInclusive.HasValue && partitionKeyHashRange.EndExclusive.HasValue) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.EmptyPartitionKeyRange); } } if (!sortedSet.Add(partitionKeyHashRange)) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.DuplicatePartitionKeyRange); } } // Need to check if the ranges overlap // This can be done by checking the overall range that the ranges cover // and comparing it to the width of all the ranges. // https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-two-integer-ranges-for-overlap UInt128 minStart = UInt128.MaxValue; UInt128 maxEnd = UInt128.MinValue; (UInt128 sumOfWidth, bool overflowed) = (0, false); foreach (PartitionKeyHashRange partitionKeyHashRange in sortedSet) { if (partitionKeyHashRange.StartInclusive.HasValue) { if (partitionKeyHashRange.StartInclusive.Value.Value < minStart) { minStart = partitionKeyHashRange.StartInclusive.Value.Value; } } else { minStart = UInt128.MinValue; } if (partitionKeyHashRange.EndExclusive.HasValue) { if (partitionKeyHashRange.EndExclusive.Value.Value > maxEnd) { maxEnd = partitionKeyHashRange.EndExclusive.Value.Value; } } else { maxEnd = UInt128.MaxValue; } UInt128 width = partitionKeyHashRange.EndExclusive.GetValueOrDefault(new PartitionKeyHash(UInt128.MaxValue)).Value - partitionKeyHashRange.StartInclusive.GetValueOrDefault(new PartitionKeyHash(UInt128.MinValue)).Value; sumOfWidth += width; if (sumOfWidth < width) { overflowed = true; } } UInt128 rangeCoverage = maxEnd - minStart; if ((rangeCoverage < sumOfWidth) || overflowed) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.RangesOverlap); } else if (rangeCoverage > sumOfWidth) { partitionedSortedEffectiveRanges = default; return(CreateOutcome.RangesAreNotContiguous); } else { partitionedSortedEffectiveRanges = new PartitionKeyHashRanges(sortedSet); return(CreateOutcome.Success); } }