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

io.deephaven.engine.table.impl.locations.util.ExecutorTableDataRefreshService Maven / Gradle / Ivy

There is a newer version: 0.37.1
Show newest version
/**
 * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
 */
package io.deephaven.engine.table.impl.locations.util;

import io.deephaven.base.stats.Counter;
import io.deephaven.base.stats.State;
import io.deephaven.base.stats.Stats;
import io.deephaven.base.stats.Value;
import io.deephaven.base.verify.Require;
import io.deephaven.engine.table.impl.locations.impl.AbstractTableLocation;
import io.deephaven.engine.table.impl.locations.impl.AbstractTableLocationProvider;
import io.deephaven.engine.table.impl.locations.impl.SubscriptionAggregator;
import io.deephaven.engine.table.impl.locations.TableDataException;
import io.deephaven.util.thread.NamingThreadFactory;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * {@link TableDataRefreshService} implementation that uses a {@link ScheduledThreadPoolExecutor}.
 */
public class ExecutorTableDataRefreshService implements TableDataRefreshService {

    private static final String NAME_PREFIX = "TableDataRefreshService-";

    private final String name;
    private final long tableLocationProviderRefreshIntervalMillis;
    private final long tableLocationRefreshIntervalMillis;

    private final ScheduledThreadPoolExecutor scheduler;

    private final Value providerSubscriptions;
    private final Value providerSubscriptionRefreshDurationNanos;
    private final Value locationSubscriptions;
    private final Value locationSubscriptionRefreshDurationNanos;

    public ExecutorTableDataRefreshService(@NotNull final String name,
            final long tableLocationProviderRefreshIntervalMillis,
            final long tableLocationRefreshIntervalMillis,
            final int threadPoolSize) {
        this.name = Require.neqNull(name, "name");
        this.tableLocationProviderRefreshIntervalMillis = Require.gtZero(tableLocationProviderRefreshIntervalMillis,
                "tableLocationProviderRefreshIntervalMillis");
        this.tableLocationRefreshIntervalMillis =
                Require.gtZero(tableLocationRefreshIntervalMillis, "tableLocationRefreshIntervalMillis");

        NamingThreadFactory threadFactory = new NamingThreadFactory(TableDataRefreshService.class, "refreshThread");
        scheduler =
                new ScheduledThreadPoolExecutor(threadPoolSize, threadFactory, new ThreadPoolExecutor.AbortPolicy());
        scheduler.setRemoveOnCancelPolicy(true);

        providerSubscriptions = Stats.makeItem(NAME_PREFIX + name, "providerSubscriptions", Counter.FACTORY).getValue();
        providerSubscriptionRefreshDurationNanos = Stats
                .makeItem(NAME_PREFIX + name, "providerSubscriptionRefreshDurationNanos", State.FACTORY).getValue();
        locationSubscriptions = Stats.makeItem(NAME_PREFIX + name, "locationSubscriptions", Counter.FACTORY).getValue();
        locationSubscriptionRefreshDurationNanos = Stats
                .makeItem(NAME_PREFIX + name, "locationSubscriptionRefreshDurationNanos", State.FACTORY).getValue();
    }

    @Override
    public void submitOneTimeAsyncTask(@NotNull final Runnable task) {
        scheduler.submit(task);
    }

    private abstract class ScheduledSubscriptionTask
            implements CancellableSubscriptionToken {

        final TYPE subscriptionAggregator;

        private final Future future;

        private volatile boolean firstInvocation = true;

        private ScheduledSubscriptionTask(@NotNull final TYPE subscriptionAggregator,
                final long refreshIntervalMillis) {
            this.subscriptionAggregator = subscriptionAggregator;
            future = scheduler.scheduleAtFixedRate(this::doRefresh, 0, refreshIntervalMillis, TimeUnit.MILLISECONDS);
        }

        private void doRefresh() {
            try {
                refresh();
            } catch (TableDataException e) {
                subscriptionAggregator.activationFailed(this, e);
            } catch (Throwable t) {
                subscriptionAggregator.activationFailed(this, new TableDataException("Unexpected error", t));
            }
            if (firstInvocation) {
                firstInvocation = false;
                subscriptionAggregator.activationSuccessful(this);
            }
        }

        /**
         * Type-specific run processing.
         */
        protected abstract void refresh();

        @Override
        public void cancel() {
            future.cancel(false);
        }
    }

    private class ScheduledTableLocationProviderRefresh
            extends ScheduledSubscriptionTask {

        private ScheduledTableLocationProviderRefresh(@NotNull AbstractTableLocationProvider tableLocationProvider) {
            super(tableLocationProvider, tableLocationProviderRefreshIntervalMillis);
            providerSubscriptions.increment(1);
        }

        @Override
        protected void refresh() {
            final long startTimeNanos = System.nanoTime();
            subscriptionAggregator.refresh();
            providerSubscriptionRefreshDurationNanos.sample(System.nanoTime() - startTimeNanos);
        }

        @Override
        public void cancel() {
            super.cancel();
            providerSubscriptions.increment(-1);
        }
    }

    private class ScheduledTableLocationRefresh extends ScheduledSubscriptionTask {

        private ScheduledTableLocationRefresh(@NotNull AbstractTableLocation tableLocation) {
            super(tableLocation, tableLocationRefreshIntervalMillis);
            locationSubscriptions.increment(1);
        }

        @Override
        protected void refresh() {
            final long startTimeNanos = System.nanoTime();
            subscriptionAggregator.refresh();
            locationSubscriptionRefreshDurationNanos.sample(System.nanoTime() - startTimeNanos);
        }

        @Override
        public void cancel() {
            super.cancel();
            locationSubscriptions.increment(-1);
        }
    }

    @Override
    public CancellableSubscriptionToken scheduleTableLocationProviderRefresh(
            @NotNull final AbstractTableLocationProvider tableLocationProvider) {
        return new ScheduledTableLocationProviderRefresh(tableLocationProvider);
    }

    @Override
    public CancellableSubscriptionToken scheduleTableLocationRefresh(
            @NotNull final AbstractTableLocation tableLocation) {
        return new ScheduledTableLocationRefresh(tableLocation);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy