All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.azure.cosmos.implementation.routing.RoutingMapProviderHelper Maven / Gradle / Ivy

Go to download

This Package contains Microsoft Azure Cosmos SDK (with Reactive Extension Reactor support) for Azure Cosmos DB SQL API

There is a newer version: 4.61.1
Show newest version
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.cosmos.implementation.routing;

import com.azure.cosmos.implementation.IRoutingMapProvider;
import com.azure.cosmos.implementation.PartitionKeyRange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.TreeSet;

/**
 * Provide utility functionality to route request in direct connectivity mode in the Azure Cosmos DB database service.
 */
public final class RoutingMapProviderHelper {
    private static final Range.MaxComparator MAX_COMPARATOR = new Range.MaxComparator();

    private static String max(String left, String right) {
        return left.compareTo(right) < 0 ? right : left;
    }

    private static > boolean isSortedAndNonOverlapping(List> list) {
        for (int i = 1; i < list.size(); i++) {
            Range previousRange = list.get(i - 1);
            Range currentRange = list.get(i);

            int compareResult = previousRange.getMax().compareTo(currentRange.getMin());
            if (compareResult > 0) {
                return false;
            } else if (compareResult == 0 && previousRange.isMaxInclusive() && currentRange.isMinInclusive()) {
                return false;
            }
        }

        return true;
    }

    public static Collection getOverlappingRanges(RoutingMapProvider routingMapProvider,
            String collectionSelfLink, List> sortedRanges) {
        if (!isSortedAndNonOverlapping(sortedRanges)) {
            throw new IllegalArgumentException("sortedRanges");
        }

        List targetRanges = new ArrayList();
        int currentProvidedRange = 0;
        while (currentProvidedRange < sortedRanges.size()) {
            if (sortedRanges.get(currentProvidedRange).isEmpty()) {
                currentProvidedRange++;
                continue;
            }

            Range queryRange;
            if (!targetRanges.isEmpty()) {
                String left = max(targetRanges.get(targetRanges.size() - 1).getMaxExclusive(),
                        sortedRanges.get(currentProvidedRange).getMin());

                boolean leftInclusive = left.compareTo(sortedRanges.get(currentProvidedRange).getMin()) == 0
                        ? sortedRanges.get(currentProvidedRange).isMinInclusive() : false;

                queryRange = new Range(left, sortedRanges.get(currentProvidedRange).getMax(), leftInclusive,
                        sortedRanges.get(currentProvidedRange).isMaxInclusive());
            } else {
                queryRange = sortedRanges.get(currentProvidedRange);
            }

            targetRanges.addAll(routingMapProvider.getOverlappingRanges(collectionSelfLink, queryRange, false));

            Range lastKnownTargetRange = targetRanges.get(targetRanges.size() - 1).toRange();
            while (currentProvidedRange < sortedRanges.size()
                    && MAX_COMPARATOR.compare(sortedRanges.get(currentProvidedRange), lastKnownTargetRange) <= 0) {
                currentProvidedRange++;
            }
        }

        return targetRanges;
    }

    public static Mono> getOverlappingRanges(
        IRoutingMapProvider routingMapProvider,
        String resourceId, List> sortedRanges) {

        if (routingMapProvider == null){
            throw new IllegalArgumentException("routingMapProvider");
        }

        if (sortedRanges == null) {
            throw new IllegalArgumentException("sortedRanges");
        }

        // Removing duplicates from sortedranges to check for nonoverlap
        TreeSet> distinctSortedRanges = new TreeSet<>(new Range.MinComparator<>());
        distinctSortedRanges.addAll(sortedRanges);

        if (!isSortedAndNonOverlapping(new ArrayList<>(distinctSortedRanges))) {
            throw new IllegalArgumentException("sortedRanges");
        }

        List targetRanges = new ArrayList<>();
        final ListIterator> iterator = sortedRanges.listIterator();

        return Flux.defer(() -> {
            if (!iterator.hasNext()) {
                return Flux.empty();
            }

            Range queryRange;
            Range sortedRange = iterator.next();
            if (!targetRanges.isEmpty()) {
                String left = max(targetRanges.get(targetRanges.size() - 1).getMaxExclusive(),
                                  sortedRange.getMin());

                boolean leftInclusive = left.compareTo(sortedRange.getMin()) == 0 && sortedRange.isMinInclusive();

                queryRange = new Range(left, sortedRange.getMax(), leftInclusive,
                                               sortedRange.isMaxInclusive());
            } else {
                queryRange = sortedRange;
            }

            return routingMapProvider.tryGetOverlappingRangesAsync(null, resourceId, queryRange, false, null)
                       .map(ranges -> ranges.v)
                       .map(targetRanges::addAll)
                       .flatMap(aBoolean -> {
                           if (!targetRanges.isEmpty()) {
                               Range lastKnownTargetRange = targetRanges.get(targetRanges.size() - 1).toRange();
                               while (iterator.hasNext()) {
                                   Range value = iterator.next();
                                   if (MAX_COMPARATOR.compare(value, lastKnownTargetRange) > 0) {
                                       // Since we already moved forward on iterator to check above condition, we
                                       // go to previous when it fails so the the value is not skipped on iteration
                                       iterator.previous();
                                       break;
                                   }
                               }
                           }
                           return Mono.just(targetRanges);
                       }).flux();
        }).repeat(sortedRanges.size())
                   .takeUntil(stringRange -> !iterator.hasNext())
                   .last()
                   .single();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy