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

io.deephaven.server.table.ops.RangeJoinGrpcImpl Maven / Gradle / Ivy

The newest version!
//
// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
//
package io.deephaven.server.table.ops;

import com.google.protobuf.Descriptors;
import com.google.rpc.Code;
import io.deephaven.api.ColumnName;
import io.deephaven.api.JoinMatch;
import io.deephaven.api.RangeEndRule;
import io.deephaven.api.RangeJoinMatch;
import io.deephaven.api.RangeStartRule;
import io.deephaven.auth.codegen.impl.TableServiceContextualAuthWiring;
import io.deephaven.base.verify.Assert;
import io.deephaven.engine.table.Table;
import io.deephaven.proto.backplane.grpc.Aggregation;
import io.deephaven.proto.backplane.grpc.BatchTableRequest;
import io.deephaven.proto.backplane.grpc.RangeJoinTablesRequest;
import io.deephaven.proto.backplane.grpc.TableReference;
import io.deephaven.proto.util.Exceptions;
import io.deephaven.server.grpc.Common;
import io.deephaven.server.grpc.GrpcErrorHelper;
import io.deephaven.server.session.SessionState.ExportObject;
import io.grpc.StatusRuntimeException;
import org.jetbrains.annotations.NotNull;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Singleton
public final class RangeJoinGrpcImpl extends GrpcTableOperation {

    @Inject
    public RangeJoinGrpcImpl(
            final TableServiceContextualAuthWiring authWiring) {
        super(
                authWiring::checkPermissionRangeJoinTables,
                BatchTableRequest.Operation::getRangeJoin,
                RangeJoinTablesRequest::getResultId,
                RangeJoinGrpcImpl::refs);
    }

    private static List refs(RangeJoinTablesRequest request) {
        return List.of(request.getLeftId(), request.getRightId());
    }

    @Override
    public void validateRequest(RangeJoinTablesRequest request) throws StatusRuntimeException {
        GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.LEFT_ID_FIELD_NUMBER);
        GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.RIGHT_ID_FIELD_NUMBER);

        // Validate that the `range_match` field is set OR the range detail fields are set
        if (!hasRangeMatchString(request)) {
            GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.LEFT_START_COLUMN_FIELD_NUMBER);
            GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.RANGE_START_RULE_FIELD_NUMBER);
            GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.RIGHT_RANGE_COLUMN_FIELD_NUMBER);
            GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.RANGE_END_RULE_FIELD_NUMBER);
            GrpcErrorHelper.checkHasField(request, RangeJoinTablesRequest.LEFT_END_COLUMN_FIELD_NUMBER);
        } else {
            try {
                GrpcErrorHelper.checkDoesNotHaveField(request, RangeJoinTablesRequest.LEFT_START_COLUMN_FIELD_NUMBER);
                GrpcErrorHelper.checkDoesNotHaveField(request, RangeJoinTablesRequest.RANGE_START_RULE_FIELD_NUMBER);
                GrpcErrorHelper.checkDoesNotHaveField(request, RangeJoinTablesRequest.RIGHT_RANGE_COLUMN_FIELD_NUMBER);
                GrpcErrorHelper.checkDoesNotHaveField(request, RangeJoinTablesRequest.RANGE_END_RULE_FIELD_NUMBER);
                GrpcErrorHelper.checkDoesNotHaveField(request, RangeJoinTablesRequest.LEFT_END_COLUMN_FIELD_NUMBER);
            } catch (Exception ex) {
                throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
                        "If `range_match` is provided, range details should remain empty. \nInternal error: "
                                + ex.getMessage());
            }
        }

        GrpcErrorHelper.checkRepeatedFieldNonEmpty(request, RangeJoinTablesRequest.AGGREGATIONS_FIELD_NUMBER);

        GrpcErrorHelper.checkHasNoUnknownFields(request);

        Common.validate(request.getLeftId());
        Common.validate(request.getRightId());

        try {
            for (String exactMatch : request.getExactMatchColumnsList()) {
                JoinMatch.parse(exactMatch);
            }
            if (!hasRangeMatchString(request)) {
                adaptRangeMatch(request);
            } else {
                // Parse the string and throw an exception if it's invalid
                RangeJoinMatch.parse(request.getRangeMatch());
            }
        } catch (IllegalArgumentException e) {
            throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT, e.getMessage());
        }

        for (Aggregation aggregation : request.getAggregationsList()) {
            AggregationAdapter.validate(aggregation);
        }
    }

    @Override
    public Table create(RangeJoinTablesRequest request, List> sourceTables) {
        Assert.eq(sourceTables.size(), "sourceTables.size()", 2);
        Assert.gtZero(request.getAggregationsCount(), "request.getAggregationsCount()");

        final Table leftTable = sourceTables.get(0).get();
        final Table rightTable = sourceTables.get(1).get();
        final Collection exactMatches = JoinMatch.from(request.getExactMatchColumnsList());
        final RangeJoinMatch rangeMatch;
        if (!hasRangeMatchString(request)) {
            rangeMatch = adaptRangeMatch(request);
        } else {
            rangeMatch = RangeJoinMatch.parse(request.getRangeMatch());
        }
        final Collection aggregations = request.getAggregationsList()
                .stream()
                .map(AggregationAdapter::adapt)
                .collect(Collectors.toList());

        if (!leftTable.isRefreshing() && !rightTable.isRefreshing()) {
            return leftTable.rangeJoin(rightTable, exactMatches, rangeMatch, aggregations);
        } else {
            return leftTable.getUpdateGraph(rightTable).sharedLock().computeLocked(
                    () -> leftTable.rangeJoin(rightTable, exactMatches, rangeMatch, aggregations));
        }
    }

    private static boolean hasRangeMatchString(@NotNull final RangeJoinTablesRequest message) {
        final Descriptors.Descriptor descriptor = message.getDescriptorForType();
        final Descriptors.FieldDescriptor fieldDescriptor =
                descriptor.findFieldByNumber(RangeJoinTablesRequest.RANGE_MATCH_FIELD_NUMBER);
        return message.hasField(fieldDescriptor);
    }

    private static RangeJoinMatch adaptRangeMatch(@NotNull final RangeJoinTablesRequest request) {
        return RangeJoinMatch.of(
                ColumnName.parse(request.getLeftStartColumn()),
                adapt(request.getRangeStartRule()),
                ColumnName.parse(request.getRightRangeColumn()),
                adapt(request.getRangeEndRule()),
                ColumnName.parse(request.getLeftEndColumn()));
    }

    private static RangeStartRule adapt(RangeJoinTablesRequest.RangeStartRule rule) {
        switch (rule) {
            case LESS_THAN:
                return RangeStartRule.LESS_THAN;
            case LESS_THAN_OR_EQUAL:
                return RangeStartRule.LESS_THAN_OR_EQUAL;
            case LESS_THAN_OR_EQUAL_ALLOW_PRECEDING:
                return RangeStartRule.LESS_THAN_OR_EQUAL_ALLOW_PRECEDING;
            default:
                throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
                        String.format("Unrecognized range start rule %s for range join", rule));
        }
    }

    private static RangeEndRule adapt(RangeJoinTablesRequest.RangeEndRule rule) {
        switch (rule) {
            case GREATER_THAN:
                return RangeEndRule.GREATER_THAN;
            case GREATER_THAN_OR_EQUAL:
                return RangeEndRule.GREATER_THAN_OR_EQUAL;
            case GREATER_THAN_OR_EQUAL_ALLOW_FOLLOWING:
                return RangeEndRule.GREATER_THAN_OR_EQUAL_ALLOW_FOLLOWING;
            default:
                throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
                        String.format("Unrecognized range end rule %s for range join", rule));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy