PulseId-GlobalTime mapping.
This commit is contained in:
@ -54,10 +54,12 @@ import ch.psi.daq.domain.query.DAQConfigQueryElement;
|
|||||||
import ch.psi.daq.domain.query.DAQQueries;
|
import ch.psi.daq.domain.query.DAQQueries;
|
||||||
import ch.psi.daq.domain.query.DAQQuery;
|
import ch.psi.daq.domain.query.DAQQuery;
|
||||||
import ch.psi.daq.domain.query.DAQQueryElement;
|
import ch.psi.daq.domain.query.DAQQueryElement;
|
||||||
|
import ch.psi.daq.domain.query.RangeQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQuery;
|
import ch.psi.daq.domain.query.backend.BackendQuery;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelConfigurationsRequest;
|
import ch.psi.daq.domain.query.channels.ChannelConfigurationsRequest;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
||||||
import ch.psi.daq.domain.query.channels.LongHash;
|
import ch.psi.daq.domain.query.channels.LongHash;
|
||||||
|
import ch.psi.daq.domain.query.channels.RangeQueryResponse;
|
||||||
import ch.psi.daq.domain.query.operation.Aggregation;
|
import ch.psi.daq.domain.query.operation.Aggregation;
|
||||||
import ch.psi.daq.domain.query.operation.AggregationType;
|
import ch.psi.daq.domain.query.operation.AggregationType;
|
||||||
import ch.psi.daq.domain.query.operation.Compression;
|
import ch.psi.daq.domain.query.operation.Compression;
|
||||||
@ -250,11 +252,13 @@ public class QueryRestController implements ApplicationContextAware {
|
|||||||
final Supplier<Collection<ChannelName>> channelsSupplier = () -> query.getChannels();
|
final Supplier<Collection<ChannelName>> channelsSupplier = () -> query.getChannels();
|
||||||
final String redirect = queryManager.getRedirection(channelsSupplier);
|
final String redirect = queryManager.getRedirection(channelsSupplier);
|
||||||
if (redirect != null) {
|
if (redirect != null) {
|
||||||
final String redirectURL =
|
final String redirectURL =
|
||||||
redirect
|
redirect
|
||||||
+ httpRequest.getRequestURI()
|
+ httpRequest.getRequestURI()
|
||||||
+ ((httpRequest.getQueryString() != null && StringUtils.NULL_STRING.equals(httpRequest.getQueryString())) ? StringUtils.QUESTION_MARK + httpRequest.getQueryString()
|
+ ((httpRequest.getQueryString() != null
|
||||||
: StringUtils.EMPTY);
|
&& StringUtils.NULL_STRING.equals(httpRequest.getQueryString()))
|
||||||
|
? StringUtils.QUESTION_MARK + httpRequest.getQueryString()
|
||||||
|
: StringUtils.EMPTY);
|
||||||
|
|
||||||
LOGGER.info("Send redirect to '{}'.", redirectURL);
|
LOGGER.info("Send redirect to '{}'.", redirectURL);
|
||||||
httpResponse.setHeader(HttpHeaders.LOCATION, redirectURL);
|
httpResponse.setHeader(HttpHeaders.LOCATION, redirectURL);
|
||||||
@ -433,11 +437,13 @@ public class QueryRestController implements ApplicationContextAware {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
final String redirect = queryManager.getRedirection(channelsSupplier);
|
final String redirect = queryManager.getRedirection(channelsSupplier);
|
||||||
if (redirect != null) {
|
if (redirect != null) {
|
||||||
final String redirectURL =
|
final String redirectURL =
|
||||||
redirect
|
redirect
|
||||||
+ httpRequest.getRequestURI()
|
+ httpRequest.getRequestURI()
|
||||||
+ ((httpRequest.getQueryString() != null && StringUtils.NULL_STRING.equals(httpRequest.getQueryString())) ? StringUtils.QUESTION_MARK + httpRequest.getQueryString()
|
+ ((httpRequest.getQueryString() != null
|
||||||
: StringUtils.EMPTY);
|
&& StringUtils.NULL_STRING.equals(httpRequest.getQueryString()))
|
||||||
|
? StringUtils.QUESTION_MARK + httpRequest.getQueryString()
|
||||||
|
: StringUtils.EMPTY);
|
||||||
|
|
||||||
LOGGER.info("Send redirect to '{}'.", redirectURL);
|
LOGGER.info("Send redirect to '{}'.", redirectURL);
|
||||||
httpResponse.setHeader(HttpHeaders.LOCATION, redirectURL);
|
httpResponse.setHeader(HttpHeaders.LOCATION, redirectURL);
|
||||||
@ -479,6 +485,48 @@ public class QueryRestController implements ApplicationContextAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
value = DomainConfig.PATH_QUERY_RANGE,
|
||||||
|
method = RequestMethod.POST,
|
||||||
|
consumes = {MediaType.APPLICATION_JSON_VALUE})
|
||||||
|
public Stream<RangeQueryResponse> queryRange(
|
||||||
|
@RequestBody @Valid final RangeQuery rangeQuery,
|
||||||
|
final HttpServletRequest httpRequest,
|
||||||
|
final HttpServletResponse httpResponse) throws Exception {
|
||||||
|
|
||||||
|
final Response response = rangeQuery.getResponseOrDefault(defaultResponse);
|
||||||
|
if (response.isAllowRedirect()) {
|
||||||
|
// Do a redirection if only one backend is requested
|
||||||
|
//
|
||||||
|
final Supplier<Collection<ChannelName>> channelsSupplier = () -> rangeQuery.getChannels();
|
||||||
|
final String redirect = queryManager.getRedirection(channelsSupplier);
|
||||||
|
if (redirect != null) {
|
||||||
|
final String redirectURL =
|
||||||
|
redirect
|
||||||
|
+ httpRequest.getRequestURI()
|
||||||
|
+ ((httpRequest.getQueryString() != null
|
||||||
|
&& StringUtils.NULL_STRING.equals(httpRequest.getQueryString()))
|
||||||
|
? StringUtils.QUESTION_MARK + httpRequest.getQueryString()
|
||||||
|
: StringUtils.EMPTY);
|
||||||
|
|
||||||
|
LOGGER.info("Send redirect to '{}'.", redirectURL);
|
||||||
|
httpResponse.setHeader(HttpHeaders.LOCATION, redirectURL);
|
||||||
|
// use 307 - works for POST too
|
||||||
|
httpResponse.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
LOGGER.debug("Executing range query '{}'", rangeQuery);
|
||||||
|
|
||||||
|
return queryManager.queryRange(rangeQuery);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to execute range query '{}'.", rangeQuery, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current list of {@link Ordering}s available.
|
* Returns the current list of {@link Ordering}s available.
|
||||||
*
|
*
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
package ch.psi.daq.queryrest.query;
|
package ch.psi.daq.queryrest.query;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
|
|
||||||
|
import ch.psi.daq.common.ordering.Ordering;
|
||||||
import ch.psi.daq.common.tuple.Quadruple;
|
import ch.psi.daq.common.tuple.Quadruple;
|
||||||
import ch.psi.daq.domain.DataEvent;
|
import ch.psi.daq.domain.DataEvent;
|
||||||
|
import ch.psi.daq.domain.PulseIdTime;
|
||||||
import ch.psi.daq.domain.backend.Backend;
|
import ch.psi.daq.domain.backend.Backend;
|
||||||
|
import ch.psi.daq.domain.backend.BackendAccess;
|
||||||
|
import ch.psi.daq.domain.config.DomainConfig;
|
||||||
import ch.psi.daq.domain.events.ChannelConfiguration;
|
import ch.psi.daq.domain.events.ChannelConfiguration;
|
||||||
import ch.psi.daq.domain.json.ChannelName;
|
import ch.psi.daq.domain.json.ChannelName;
|
||||||
import ch.psi.daq.domain.query.DAQConfigQuery;
|
import ch.psi.daq.domain.query.DAQConfigQuery;
|
||||||
import ch.psi.daq.domain.query.DAQConfigQueryElement;
|
import ch.psi.daq.domain.query.DAQConfigQueryElement;
|
||||||
import ch.psi.daq.domain.query.DAQQueries;
|
import ch.psi.daq.domain.query.DAQQueries;
|
||||||
import ch.psi.daq.domain.query.DAQQueryElement;
|
import ch.psi.daq.domain.query.DAQQueryElement;
|
||||||
|
import ch.psi.daq.domain.query.RangeQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQuery;
|
import ch.psi.daq.domain.query.backend.BackendQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQueryImpl;
|
import ch.psi.daq.domain.query.backend.BackendQueryImpl;
|
||||||
import ch.psi.daq.domain.query.backend.analyzer.BackendQueryAnalyzer;
|
import ch.psi.daq.domain.query.backend.analyzer.BackendQueryAnalyzer;
|
||||||
@ -29,9 +41,14 @@ import ch.psi.daq.domain.query.channels.ChannelConfigurationsResponse;
|
|||||||
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelsResponse;
|
import ch.psi.daq.domain.query.channels.ChannelsResponse;
|
||||||
import ch.psi.daq.domain.query.channels.LongHash;
|
import ch.psi.daq.domain.query.channels.LongHash;
|
||||||
|
import ch.psi.daq.domain.query.channels.RangeQueryResponse;
|
||||||
|
import ch.psi.daq.domain.query.operation.EventField;
|
||||||
import ch.psi.daq.domain.query.processor.QueryProcessor;
|
import ch.psi.daq.domain.query.processor.QueryProcessor;
|
||||||
|
import ch.psi.daq.domain.reader.RequestRangeQueryResult;
|
||||||
|
|
||||||
public abstract class AbstractQueryManager implements QueryManager {
|
public abstract class AbstractQueryManager implements QueryManager {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractQueryManager.class);
|
||||||
|
|
||||||
private BackendsChannelConfigurationCache channelsCache;
|
private BackendsChannelConfigurationCache channelsCache;
|
||||||
private Function<BackendQuery, BackendQueryAnalyzer> queryAnalizerFactory;
|
private Function<BackendQuery, BackendQueryAnalyzer> queryAnalizerFactory;
|
||||||
|
|
||||||
@ -176,4 +193,107 @@ public abstract class AbstractQueryManager implements QueryManager {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<RangeQueryResponse> queryRange(final RangeQuery rangeQuery) throws Exception {
|
||||||
|
if (rangeQuery.getChannels().isEmpty()) {
|
||||||
|
// query for the general (not channel specific) pulseId/globalTime
|
||||||
|
final BackendAccess backendAccess = getConfigurationCache().getDefaultBackend().getBackendAccess();
|
||||||
|
if (backendAccess.hasStreamEventReader()) {
|
||||||
|
final CompletableFuture<RequestRangeQueryResult> future =
|
||||||
|
backendAccess.getStreamEventReader().getPulseIdTimeMappingAsync(rangeQuery.getRange());
|
||||||
|
final RequestRangeQueryResult result = future.get(
|
||||||
|
backendAccess.getBackend().getApplicationContext()
|
||||||
|
.getBean(DomainConfig.BEAN_NAME_DISTRIBUTED_READ_TIMEOUT, Integer.class),
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
return Stream.of(
|
||||||
|
new RangeQueryResponse(
|
||||||
|
new ChannelName(ChannelConfiguration.COMBINED_CHANNEL_NAME, backendAccess.getBackend()),
|
||||||
|
new PulseIdTime(result.getStart(), false),
|
||||||
|
new PulseIdTime(result.getEnd(), false)));
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("Backend '{}' has no StreamEventReader. Cannot execute '{}'.", backendAccess.getBackend(),
|
||||||
|
rangeQuery);
|
||||||
|
return Stream.of(
|
||||||
|
new RangeQueryResponse(
|
||||||
|
new ChannelName(ChannelConfiguration.COMBINED_CHANNEL_NAME, backendAccess.getBackend()),
|
||||||
|
null,
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// set backends if not defined yet
|
||||||
|
getConfigurationCache().configureBackends(rangeQuery.getChannels());
|
||||||
|
|
||||||
|
final LinkedHashSet<EventField> eventFields = new LinkedHashSet<>(2);
|
||||||
|
eventFields.add(EventField.pulseId);
|
||||||
|
eventFields.add(EventField.globalTime);
|
||||||
|
eventFields.add(EventField.globalDate);
|
||||||
|
eventFields.add(EventField.globalSeconds);
|
||||||
|
rangeQuery.setAggregation(null);
|
||||||
|
rangeQuery.setEventFields(eventFields);
|
||||||
|
rangeQuery.setMapping(null);
|
||||||
|
rangeQuery.setValueTransformations(null);
|
||||||
|
rangeQuery.setLimit(1);
|
||||||
|
rangeQuery.setOrdering(Ordering.asc);
|
||||||
|
|
||||||
|
Stream<Triple<ChannelName, Stream<? extends DataEvent>, Stream<? extends DataEvent>>> resultStreams =
|
||||||
|
BackendQueryImpl
|
||||||
|
.getBackendQueries(rangeQuery)
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
query -> {
|
||||||
|
return query.getBackend().getBackendAccess().hasDataReader()
|
||||||
|
&& query.getBackend().getBackendAccess().hasQueryProcessor();
|
||||||
|
})
|
||||||
|
.flatMap(
|
||||||
|
query -> {
|
||||||
|
final BackendQueryImpl queryForward = new BackendQueryImpl(query);
|
||||||
|
// queryForward.setAggregation(null);
|
||||||
|
// queryForward.setEventFields(eventFields);
|
||||||
|
// queryForward.setMapping(null);
|
||||||
|
// queryForward.setValueTransformations(null);
|
||||||
|
// queryForward.setLimit(1);
|
||||||
|
// queryForward.setOrdering(Ordering.asc);
|
||||||
|
|
||||||
|
final QueryProcessor processor =
|
||||||
|
queryForward.getBackend().getBackendAccess().getQueryProcessor();
|
||||||
|
|
||||||
|
final BackendQueryAnalyzer queryAnalizerForward =
|
||||||
|
queryAnalizerFactory.apply(queryForward);
|
||||||
|
final Stream<Entry<ChannelName, Stream<? extends DataEvent>>> channelToDataEventForward =
|
||||||
|
processor.process(queryAnalizerForward);
|
||||||
|
|
||||||
|
final BackendQueryImpl queryBackwards = new BackendQueryImpl(queryForward);
|
||||||
|
queryBackwards.setOrdering(Ordering.desc);
|
||||||
|
final BackendQueryAnalyzer queryAnalizerBackwards =
|
||||||
|
queryAnalizerFactory.apply(queryForward);
|
||||||
|
final Stream<Entry<ChannelName, Stream<? extends DataEvent>>> channelToDataEventBackwards =
|
||||||
|
processor.process(queryAnalizerBackwards);
|
||||||
|
|
||||||
|
return Streams.zip(
|
||||||
|
channelToDataEventForward,
|
||||||
|
channelToDataEventBackwards,
|
||||||
|
(entry1, entry2) -> {
|
||||||
|
return Triple.of(
|
||||||
|
entry1.getKey(),
|
||||||
|
entry1.getValue(),
|
||||||
|
entry2.getValue());
|
||||||
|
// return Triple.of(
|
||||||
|
// entry1.getKey(),
|
||||||
|
// Streams.concat(entry1.getValue(), entry2.getValue()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// make sure queries are executed (Streams populate async)
|
||||||
|
resultStreams = resultStreams.collect(Collectors.toList()).stream();
|
||||||
|
|
||||||
|
// now access internal streams (which will block until data is available)
|
||||||
|
return resultStreams
|
||||||
|
.map(triple -> {
|
||||||
|
return new RangeQueryResponse(
|
||||||
|
triple.getLeft(),
|
||||||
|
new PulseIdTime(triple.getMiddle().findFirst().orElse(null), false),
|
||||||
|
new PulseIdTime(triple.getRight().findFirst().orElse(null), false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,14 @@ import ch.psi.daq.domain.query.DAQConfigQuery;
|
|||||||
import ch.psi.daq.domain.query.DAQConfigQueryElement;
|
import ch.psi.daq.domain.query.DAQConfigQueryElement;
|
||||||
import ch.psi.daq.domain.query.DAQQueries;
|
import ch.psi.daq.domain.query.DAQQueries;
|
||||||
import ch.psi.daq.domain.query.DAQQueryElement;
|
import ch.psi.daq.domain.query.DAQQueryElement;
|
||||||
|
import ch.psi.daq.domain.query.RangeQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQuery;
|
import ch.psi.daq.domain.query.backend.BackendQuery;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelConfigurationsRequest;
|
import ch.psi.daq.domain.query.channels.ChannelConfigurationsRequest;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelConfigurationsResponse;
|
import ch.psi.daq.domain.query.channels.ChannelConfigurationsResponse;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
import ch.psi.daq.domain.query.channels.ChannelsRequest;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelsResponse;
|
import ch.psi.daq.domain.query.channels.ChannelsResponse;
|
||||||
import ch.psi.daq.domain.query.channels.LongHash;
|
import ch.psi.daq.domain.query.channels.LongHash;
|
||||||
|
import ch.psi.daq.domain.query.channels.RangeQueryResponse;
|
||||||
|
|
||||||
public interface QueryManager {
|
public interface QueryManager {
|
||||||
|
|
||||||
@ -61,4 +63,6 @@ public interface QueryManager {
|
|||||||
List<Entry<DAQQueryElement, Stream<Quadruple<BackendQuery, ChannelName, ?, ?>>>> queryEvents(
|
List<Entry<DAQQueryElement, Stream<Quadruple<BackendQuery, ChannelName, ?, ?>>>> queryEvents(
|
||||||
final DAQQueries queries)
|
final DAQQueries queries)
|
||||||
throws Exception;
|
throws Exception;
|
||||||
|
|
||||||
|
Stream<RangeQueryResponse> queryRange(final RangeQuery rangeQuery) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,13 @@ import ch.psi.daq.domain.json.ChannelName;
|
|||||||
import ch.psi.daq.domain.query.DAQQueries;
|
import ch.psi.daq.domain.query.DAQQueries;
|
||||||
import ch.psi.daq.domain.query.DAQQuery;
|
import ch.psi.daq.domain.query.DAQQuery;
|
||||||
import ch.psi.daq.domain.query.DAQQueryElement;
|
import ch.psi.daq.domain.query.DAQQueryElement;
|
||||||
|
import ch.psi.daq.domain.query.RangeQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQuery;
|
import ch.psi.daq.domain.query.backend.BackendQuery;
|
||||||
import ch.psi.daq.domain.query.backend.BackendQueryImpl;
|
import ch.psi.daq.domain.query.backend.BackendQueryImpl;
|
||||||
import ch.psi.daq.domain.query.backend.analyzer.BackendQueryAnalyzer;
|
import ch.psi.daq.domain.query.backend.analyzer.BackendQueryAnalyzer;
|
||||||
import ch.psi.daq.domain.query.channels.BackendsChannelConfigurationCache;
|
import ch.psi.daq.domain.query.channels.BackendsChannelConfigurationCache;
|
||||||
import ch.psi.daq.domain.query.channels.ChannelConfigurationLoader;
|
import ch.psi.daq.domain.query.channels.ChannelConfigurationLoader;
|
||||||
|
import ch.psi.daq.domain.query.channels.RangeQueryResponse;
|
||||||
import ch.psi.daq.domain.query.mapping.IncompleteStrategy;
|
import ch.psi.daq.domain.query.mapping.IncompleteStrategy;
|
||||||
import ch.psi.daq.domain.query.response.Response;
|
import ch.psi.daq.domain.query.response.Response;
|
||||||
import ch.psi.daq.domain.query.response.ResponseFormat;
|
import ch.psi.daq.domain.query.response.ResponseFormat;
|
||||||
@ -212,4 +214,9 @@ public class QueryManagerRemote extends AbstractQueryManager implements Applicat
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<RangeQueryResponse> queryRange(final RangeQuery rangeQuery) throws Exception {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user