// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
= Using Continuous Queries

:javaFile: {javaCodeDir}/UsingContinuousQueries.java

A continuous query is a query that monitors data modifications occurring in a cache.
Once a continuous query is started, you get notified of all the data changes that fall into your query filter.

All update events are propagated to the <<Local Listener,local listener>> that must be registered in the query.
Continuous query implementation guarantees exactly once delivery of an event to the local listener.

You can also specify a remote filter to narrow down the range of entries that are monitored for updates.

[CAUTION]
====
[discrete]
=== Continuous Queries and MVCC
Continuous queries have a number of link:transactions/mvcc[functional limitations] when used with MVCC-enabled caches.
====


== Local Listener

When a cache gets modified (an entry is inserted, updated, or deleted), an event is sent to the continuous query's local listener so that your application can react accordingly.
The local listener is executed on the node that initiated the query.

Note that the continuous query throws an exception if started without a local listener.

[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=localListener,indent=0]
----
tab:C#/.NET[]
[source,csharp]
----
include::code-snippets/dotnet/ContiniuosQueries.cs[tag=localListener,indent=0]
----

tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query_listener.cpp[tag=continuous-query-listener,indent=0]
----
--

== Initial Query

You can specify an initial query that is executed before the continuous query gets registered in the cluster and before you start to receive updates.
To specify an initial query, use the `ContinuousQuery.setInitialQuery(...)` method.

Just like scan queries, a continuous query is executed via the `query()` method that returns a cursor. When an initial query is set, you can use that cursor to iterate over the results of the initial query.


[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=initialQry,indent=0]
----
tab:C#/.NET[unsupported]
tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query.cpp[tag=continuous-query,indent=0]
----
--


== Remote Filter

This filter is executed for each updated key and evaluates whether the update should be propagated to the query's local listener.
If the filter returns `true`, then the local listener is notified about the update.

For redundancy reasons, the filter is executed for both primary and backup versions (if backups are configured) of the key.
Because of this, a remote filter can be used as a remote listener for update events.


[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=remoteFilter,indent=0]
----

tab:C#/.NET[]
[source,csharp]
----
include::code-snippets/dotnet/ContiniuosQueries.cs[tag=remoteFilter,indent=0]
----

tab:C++[]
[source,cpp]
----
include::code-snippets/cpp/src/continuous_query_filter.cpp[tag=continuous-query-filter,indent=0]
----
--


[NOTE]
====
In order to use remote filters, make sure the class definitions of the filters are available on the server nodes.
You can do this in two ways:

* Add the classes to the classpath of every server node;
* link:code-deployment/peer-class-loading[Enable peer class loading].
====


== Remote Transformer

By default, continuous queries send the whole updated object to the local listener. This can lead to excessive network usage, especially if the object is very large. Moreover, applications often need only a subset of fields of the object.

To address these cases, you can use a continuous query with a transformer. A transformer is a function that is executed on remote nodes for every updated object and sends back only the results of the transformation.

[tabs]
--
tab:Java[]
[source,java]
----
include::{javaFile}[tag=transformer,indent=0]
----
tab:C#/.NET[unsupported]
tab:C++[unsupported]
--

[NOTE]
====
In order to use transformers, make sure the class definitions of the transformers are available on the server nodes.
You can do this in two ways:

* Add the classes to the classpath of every server node;
* link:code-deployment/peer-class-loading[Enable peer class loading].
====

== Events Delivery Guarantees

Continuous queries ensure the exactly-once semantic for the delivery of events to the clients' local listeners.

Both primary and backup nodes maintain an update queue that holds events that are processed by continuous queries
on the server side but yet to be delivered to the clients. Suppose a primary node crashes
or the cluster topology changes for any reason. In that case, every backup node flushes the content of its update
queue to the client, making sure that every event is delivered to the client's local listener.

Ignite manages a special per-partition update counter that helps to avoid duplicate notifications. Once an entry in
some partition is updated, a counter for this partition is incremented on both primary and backup nodes. The value of
this counter is also sent along with the event notification to the client. Thus, the client can skip already-processed
events. Once the client confirms that an event is received, the primary and backup nodes remove the record for this event
from their backup queues.


== Examples

The following application examples show typical usage of continuous queries.

link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousQueryExample.java[CacheContinuousQueryExample.java,window=_blank]

link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousAsyncQueryExample.java[CacheContinuousAsyncQueryExample.java,window=_blank]

link:{githubUrl}/examples/src/main/java/org/apache/ignite/examples/datagrid/CacheContinuousQueryWithTransformerExample.java[CacheContinuousQueryWithTransformerExample.java,window=_blank]
