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

io.trino.plugin.memory.MemorySplitManager Maven / Gradle / Ivy

There is a newer version: 458
Show newest version
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.trino.plugin.memory;

import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import io.trino.spi.connector.ConnectorSession;
import io.trino.spi.connector.ConnectorSplit;
import io.trino.spi.connector.ConnectorSplitManager;
import io.trino.spi.connector.ConnectorSplitSource;
import io.trino.spi.connector.ConnectorTableHandle;
import io.trino.spi.connector.ConnectorTransactionHandle;
import io.trino.spi.connector.Constraint;
import io.trino.spi.connector.DynamicFilter;
import io.trino.spi.connector.FixedSplitSource;

import java.util.List;
import java.util.OptionalLong;
import java.util.concurrent.CompletableFuture;

import static com.google.common.base.MoreObjects.toStringHelper;
import static io.trino.spi.connector.DynamicFilter.NOT_BLOCKED;
import static java.util.Objects.requireNonNull;

public final class MemorySplitManager
        implements ConnectorSplitManager
{
    private final int splitsPerNode;
    private final MemoryMetadata metadata;
    private final boolean enableLazyDynamicFiltering;

    @Inject
    public MemorySplitManager(MemoryConfig config, MemoryMetadata metadata)
    {
        this.splitsPerNode = config.getSplitsPerNode();
        this.metadata = metadata;
        this.enableLazyDynamicFiltering = config.isEnableLazyDynamicFiltering();
    }

    @Override
    public ConnectorSplitSource getSplits(
            ConnectorTransactionHandle transactionHandle,
            ConnectorSession session,
            ConnectorTableHandle handle,
            DynamicFilter dynamicFilter,
            Constraint constraint)
    {
        MemoryTableHandle table = (MemoryTableHandle) handle;

        List dataFragments = metadata.getDataFragments(table.id());

        long totalRows = 0;

        ImmutableList.Builder splits = ImmutableList.builder();

        for (MemoryDataFragment dataFragment : dataFragments) {
            long rows = dataFragment.rows();
            totalRows += rows;

            if (table.limit().isPresent() && totalRows > table.limit().getAsLong()) {
                rows -= totalRows - table.limit().getAsLong();
                splits.add(new MemorySplit(table.id(), 0, 1, dataFragment.hostAddress(), rows, OptionalLong.of(rows)));
                break;
            }

            for (int i = 0; i < splitsPerNode; i++) {
                splits.add(new MemorySplit(table.id(), i, splitsPerNode, dataFragment.hostAddress(), rows, OptionalLong.empty()));
            }
        }

        ConnectorSplitSource splitSource = new FixedSplitSource(splits.build());
        if (enableLazyDynamicFiltering) {
            // Needed to avoid scheduling a stage that is waiting for dynamic filters to become available.
            // It makes no difference for pipelined execution where the stages are scheduled eagerly and there's no limit on the number of tasks running in parallel.
            // However in fault tolerant execution if the stage waiting for dynamic filters is scheduled first it may occupy all available slots leaving no resources
            // for the stage that collects dynamic filters to be scheduled effectively creating a deadlock.
            splitSource = new DelayedSplitSource(whenCompleted(dynamicFilter), splitSource);
        }
        return splitSource;
    }

    private static CompletableFuture whenCompleted(DynamicFilter dynamicFilter)
    {
        if (dynamicFilter.isAwaitable()) {
            return dynamicFilter.isBlocked().thenCompose(_ -> whenCompleted(dynamicFilter));
        }
        return NOT_BLOCKED;
    }

    private static class DelayedSplitSource
            implements ConnectorSplitSource
    {
        private final CompletableFuture delay;
        private final ConnectorSplitSource delegate;

        public DelayedSplitSource(CompletableFuture delay, ConnectorSplitSource delegate)
        {
            this.delay = requireNonNull(delay, "delay is null");
            this.delegate = requireNonNull(delegate, "delegate is null");
        }

        @Override
        public CompletableFuture getNextBatch(int maxSize)
        {
            return delay.thenCompose(_ -> delegate.getNextBatch(maxSize));
        }

        @Override
        public void close()
        {
            delegate.close();
        }

        @Override
        public boolean isFinished()
        {
            if (delay.isDone()) {
                return delegate.isFinished();
            }
            return false;
        }

        @Override
        public String toString()
        {
            return toStringHelper(this)
                    .add("delay", delay)
                    .add("delegate", delegate)
                    .toString();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy