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

io.deephaven.server.uri.BarrageTableResolver Maven / Gradle / Ivy

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

import io.deephaven.UncheckedDeephavenException;
import io.deephaven.client.impl.*;
import io.deephaven.client.impl.TableHandle.TableHandleException;
import io.deephaven.configuration.Configuration;
import io.deephaven.engine.rowset.RowSet;
import io.deephaven.engine.table.Table;
import io.deephaven.extensions.barrage.BarrageSnapshotOptions;
import io.deephaven.extensions.barrage.BarrageSubscriptionOptions;
import io.deephaven.qst.table.TableSpec;
import io.deephaven.qst.table.TicketTable;
import io.deephaven.server.session.SessionFactoryCreator;
import io.deephaven.uri.ApplicationUri;
import io.deephaven.uri.DeephavenTarget;
import io.deephaven.uri.DeephavenUri;
import io.deephaven.uri.FieldUri;
import io.deephaven.uri.QueryScopeUri;
import io.deephaven.uri.RemoteUri;
import io.deephaven.uri.StructuredUri.Visitor;
import io.deephaven.uri.resolver.UriResolver;
import io.deephaven.uri.resolver.UriResolversInstance;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.net.URI;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * The barrage table resolver is able to resolve {@link RemoteUri remote URIs} into {@link Table tables}.
 *
 * 

* For more advanced use cases, see {@link BarrageSession}. * * @see RemoteUri remote URI format */ @Singleton public final class BarrageTableResolver implements UriResolver { public static final Integer MAX_INBOUND_MESSAGE_SIZE = Configuration.getInstance().getIntegerWithDefault( "BarrageTableResolver.maxInboundMessageSize", 100 * 1024 * 1024); // 100MB default limit /** * The default options, which uses {@link BarrageSubscriptionOptions#useDeephavenNulls()}. */ public static final BarrageSubscriptionOptions SUB_OPTIONS = BarrageSubscriptionOptions.builder() .useDeephavenNulls(true) .build(); public static final BarrageSnapshotOptions SNAP_OPTIONS = BarrageSnapshotOptions.builder() .useDeephavenNulls(true) .build(); private static final Set SCHEMES = Collections.unmodifiableSet( new HashSet<>(Arrays.asList(DeephavenUri.SECURE_SCHEME, DeephavenUri.PLAINTEXT_SCHEME))); public static BarrageTableResolver get() { return UriResolversInstance.get().find(BarrageTableResolver.class).get(); } private final SessionFactoryCreator sessionFactoryCreator; private final Map sessions; @Inject public BarrageTableResolver(SessionFactoryCreator sessionFactoryCreator) { this.sessionFactoryCreator = Objects.requireNonNull(sessionFactoryCreator); this.sessions = new ConcurrentHashMap<>(); } @Override public Set schemes() { return SCHEMES; } @Override public boolean isResolvable(URI uri) { // Note: we are lying right now when we say this supports remote proxied uri - but we are doing that so callers // can get a more specific exception with a link to the issue number. return RemoteUri.isWellFormed(uri); } @Override public Table resolve(URI uri) throws InterruptedException { try { return subscribe(RemoteUri.of(uri)).get(); } catch (TableHandleException e) { throw e.asUnchecked(); } catch (ExecutionException e) { throw new UncheckedDeephavenException(e); } } /** * Create a full-subscription to the remote URI. Uses {@link #SUB_OPTIONS}. * * @param remoteUri the remote URI * @return the subscribed table */ public Future

subscribe(RemoteUri remoteUri) throws InterruptedException, TableHandleException { final DeephavenTarget target = remoteUri.target(); final TableSpec table = RemoteResolver.of(remoteUri); return subscribe(target, table, SUB_OPTIONS); } /** * Create a full-subscription to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @return the subscribed table */ public Future
subscribe(String targetUri, TableSpec table) throws TableHandleException, InterruptedException { return subscribe(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS); } /** * Create a full-subscription to the {@code table} via the {@code target}. * * @param target the target * @param table the table * @param options the options * @return the subscribed table */ public Future
subscribe(DeephavenTarget target, TableSpec table, BarrageSubscriptionOptions options) throws TableHandleException, InterruptedException { final BarrageSession session = session(target); final BarrageSubscription sub = session.subscribe(table, options); return sub.entireTable(); } /** * Create a partial table subscription to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @param viewport the position-space viewport to use for the subscription * @param columns the columns to include in the subscription * @return the subscribed table */ public Future
subscribe(String targetUri, TableSpec table, RowSet viewport, BitSet columns) throws TableHandleException, InterruptedException { return subscribe(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS, viewport, columns, false); } /** * Create a partial table subscription to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @param viewport the position-space viewport to use for the subscription * @param columns the columns to include in the subscription * @param reverseViewport Whether to treat {@code viewport} as offsets from {@link Table#size()} rather than * {@code 0} * @return the subscribed table */ public Future
subscribe(String targetUri, TableSpec table, RowSet viewport, BitSet columns, boolean reverseViewport) throws TableHandleException, InterruptedException { return subscribe(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS, viewport, columns, reverseViewport); } /** * Create a partial table subscription to the {@code table} via the {@code target}. * * @param target the target * @param table the table * @param options the options * @param viewport the position-space viewport to use for the subscription * @param columns the columns to include in the subscription * @param reverseViewport Whether to treat {@code viewport} as offsets from {@link Table#size()} rather than * {@code 0} * @return the subscribed table */ public Future
subscribe(DeephavenTarget target, TableSpec table, BarrageSubscriptionOptions options, RowSet viewport, BitSet columns, boolean reverseViewport) throws TableHandleException, InterruptedException { final BarrageSession session = session(target); final BarrageSubscription sub = session.subscribe(table, options); return sub.partialTable(viewport, columns, reverseViewport); } /// NOTE: the following snapshot functions use the `BarrageSubscription` snapshot functions which leverage /// `BarrageSubscriptionRequest` and row deltas to remain consistent while the snapshot is being created. /// This is the most efficient way (for both server and client) to collect a consistent snapshot of a refreshing /// table. /** * Create a full snapshot of the remote URI. Uses {@link #SUB_OPTIONS}. * * @param remoteUri the remote URI * @return the table to snapshot */ public Future
snapshot(RemoteUri remoteUri) throws InterruptedException, TableHandleException { final DeephavenTarget target = remoteUri.target(); final TableSpec table = RemoteResolver.of(remoteUri); return snapshot(target, table, SUB_OPTIONS); } /** * Create a full snapshot to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @return the table to snapshot */ public Future
snapshot(String targetUri, TableSpec table) throws TableHandleException, InterruptedException { return snapshot(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS); } /** * Create a full snapshot to the {@code table} via the {@code target}. * * @param target the target * @param table the table * @param options the options * @return the table to snapshot */ public Future
snapshot(DeephavenTarget target, TableSpec table, BarrageSubscriptionOptions options) throws TableHandleException, InterruptedException { final BarrageSession session = session(target); return session.subscribe(table, options).snapshotEntireTable(); } /** * Create a partial table snapshot to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @param viewport the position-space viewport to use for the snapshot * @param columns the columns to include in the snapshot * @return the table to snapshot */ public Future
snapshot(String targetUri, TableSpec table, RowSet viewport, BitSet columns) throws TableHandleException, InterruptedException { return snapshot(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS, viewport, columns, false); } /** * Create a partial table snapshot to the {@code table} via the {@code targetUri}. Uses {@link #SUB_OPTIONS}. * * @param targetUri the target URI * @param table the table spec * @param viewport the position-space viewport to use for the snapshot * @param columns the columns to include in the snapshot * @param reverseViewport Whether to treat {@code viewport} as offsets from {@link Table#size()} rather than * {@code 0} * @return the table to snapshot */ public Future
snapshot(String targetUri, TableSpec table, RowSet viewport, BitSet columns, boolean reverseViewport) throws TableHandleException, InterruptedException { return snapshot(DeephavenTarget.of(URI.create(targetUri)), table, SUB_OPTIONS, viewport, columns, reverseViewport); } /** * Create a partial table snapshot to the {@code table} via the {@code target}. * * @param target the target * @param table the table * @param options the options * @param viewport the position-space viewport to use for the snapshot * @param columns the columns to include in the snapshot * @param reverseViewport Whether to treat {@code viewport} as offsets from {@link Table#size()} rather than * {@code 0} * @return the table to snapshot */ public Future
snapshot(DeephavenTarget target, TableSpec table, BarrageSubscriptionOptions options, RowSet viewport, BitSet columns, boolean reverseViewport) throws TableHandleException, InterruptedException { final BarrageSession session = session(target); return session.subscribe(table, options).snapshotPartialTable(viewport, columns, reverseViewport); } private BarrageSession session(DeephavenTarget target) { // TODO (deephaven-core#1482): BarrageTableResolver cleanup return sessions.computeIfAbsent(target, this::newSession); } private BarrageSession newSession(DeephavenTarget target) { return newSession(ClientConfig.builder() .target(target) .maxInboundMessageSize(MAX_INBOUND_MESSAGE_SIZE) .build()); } private BarrageSession newSession(ClientConfig config) { // TODO(deephaven-core#3421): DH URI / BarrageTableResolver authentication support return sessionFactoryCreator.barrageFactory(config).newBarrageSession(); } static class RemoteResolver implements Visitor { public static TableSpec of(RemoteUri remoteUri) { return remoteUri.uri().walk(new RemoteResolver(remoteUri.target())).out(); } private final DeephavenTarget target; private TableSpec out; public RemoteResolver(DeephavenTarget target) { this.target = Objects.requireNonNull(target); } public TableSpec out() { return Objects.requireNonNull(out); } @Override public void visit(FieldUri fieldUri) { out = TicketTable.fromApplicationField(target.host(), fieldUri.fieldName()); } @Override public void visit(ApplicationUri applicationField) { out = TicketTable.fromApplicationField(applicationField.applicationId(), applicationField.fieldName()); } @Override public void visit(QueryScopeUri queryScope) { out = TicketTable.fromQueryScopeField(queryScope.variableName()); } @Override public void visit(RemoteUri remoteUri) { // TODO(deephaven-core#1483): Support resolve URI via gRPC / QST throw new UnsupportedOperationException( "Proxying not supported yet, see https://github.com/deephaven/deephaven-core/issues/1483"); } @Override public void visit(URI customUri) { // TODO(deephaven-core#1483): Support resolve URI via gRPC / QST throw new UnsupportedOperationException( "Remote custom URIs not supported yet, see https://github.com/deephaven/deephaven-core/issues/1483"); } } }