use of org.apache.kafka.common.annotation.InterfaceStability.Evolving in project kafka by apache.
the class KafkaStreams method query.
/**
* Run an interactive query against a state store.
* <p>
* This method allows callers outside of the Streams runtime to access the internal state of
* stateful processors. See https://kafka.apache.org/documentation/streams/developer-guide/interactive-queries.html
* for more information.
*
* @param <R> The result type specified by the query.
* @throws StreamsNotStartedException If Streams has not yet been started. Just call {@link
* KafkaStreams#start()} and then retry this call.
* @throws StreamsStoppedException If Streams is in a terminal state like PENDING_SHUTDOWN,
* NOT_RUNNING, PENDING_ERROR, or ERROR. The caller should
* discover a new instance to query.
* @throws UnknownStateStoreException If the specified store name does not exist in the
* topology.
*/
@Evolving
public <R> StateQueryResult<R> query(final StateQueryRequest<R> request) {
final String storeName = request.getStoreName();
if (!topologyMetadata.hasStore(storeName)) {
throw new UnknownStateStoreException("Cannot get state store " + storeName + " because no such store is registered in the topology.");
}
if (state().hasNotStarted()) {
throw new StreamsNotStartedException("KafkaStreams has not been started, you can retry after calling start().");
}
if (state().isShuttingDown() || state.hasCompletedShutdown()) {
throw new StreamsStoppedException("KafkaStreams has been stopped (" + state + ")." + " This instance can no longer serve queries.");
}
final StateQueryResult<R> result = new StateQueryResult<>();
final Map<String, StateStore> globalStateStores = topologyMetadata.globalStateStores();
if (globalStateStores.containsKey(storeName)) {
// See KAFKA-13523
result.setGlobalResult(QueryResult.forFailure(FailureReason.UNKNOWN_QUERY_TYPE, "Global stores do not yet support the KafkaStreams#query API. Use KafkaStreams#store instead."));
} else {
for (final StreamThread thread : threads) {
final Map<TaskId, Task> tasks = thread.allTasks();
for (final Entry<TaskId, Task> entry : tasks.entrySet()) {
final TaskId taskId = entry.getKey();
final int partition = taskId.partition();
if (request.isAllPartitions() || request.getPartitions().contains(partition)) {
final Task task = entry.getValue();
final StateStore store = task.getStore(storeName);
if (store != null) {
final StreamThread.State state = thread.state();
final boolean active = task.isActive();
if (request.isRequireActive() && (state != StreamThread.State.RUNNING || !active)) {
result.addResult(partition, QueryResult.forFailure(FailureReason.NOT_ACTIVE, "Query requires a running active task," + " but partition was in state " + state + " and was " + (active ? "active" : "not active") + "."));
} else {
final QueryResult<R> r = store.query(request.getQuery(), request.isRequireActive() ? PositionBound.unbounded() : request.getPositionBound(), new QueryConfig(request.executionInfoEnabled()));
result.addResult(partition, r);
}
// we can return right away.
if (!request.isAllPartitions() && result.getPartitionResults().keySet().containsAll(request.getPartitions())) {
return result;
}
}
}
}
}
}
if (!request.isAllPartitions()) {
for (final Integer partition : request.getPartitions()) {
if (!result.getPartitionResults().containsKey(partition)) {
result.addResult(partition, QueryResult.forFailure(FailureReason.NOT_PRESENT, "The requested partition was not present at the time of the query."));
}
}
}
return result;
}
Aggregations