| --- |
| title: Continuous Queries |
| --- |
| |
| <!-- |
| 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. |
| --> |
| |
| The C++ and .NET clients can initiate queries that run on the <%=vars.product_name%> cache server |
| and notify the client when the query results have changed. For details on the server-side setup for |
| continuous queries, see [How Continuous Querying Works](serverman/developing/continuous_querying/how_continuous_querying_works.html) |
| in the *<%=vars.product_name%> User Guide*. |
| |
| ## <a id="cq_main_features" ></a>Continuous Query Basics |
| |
| Continuous querying provides the following features: |
| |
| - **Standard <%=vars.product_name%> native client query syntax and semantics**. Continuous queries are expressed in the same language used for other native client queries. See [Remote Queries](remote-queries.html). |
| |
| - **Standard <%=vars.product_name%> events-based management of CQ events**. The event handling used |
| to process CQ events is based on the standard <%=vars.product_name%> event handling framework. |
| |
| - **Complete integration with the client/server architecture**. CQ functionality uses existing |
| server-to-client messaging mechanisms to send events. All tuning of your server-to-client |
| messaging also tunes the messaging of your CQ events. If your system is configured for high |
| availability then your CQs are highly available, with seamless failover provided in case of |
| server failure (see [High Availability for Client-to-Server Communication](preserving-data/high-availability-client-server.html)). |
| If your clients are durable, you can also define any of your CQs as durable (see [Durable Client Messaging](preserving-data/durable-client-messaging.html)). |
| |
| - **Interest criteria based on data values**. Continuous queries are run against the region's entry values. |
| Compare this to register interest by reviewing [Registering Interest for Entries](regions/registering-interest-for-entries.html). |
| |
| - **Active query execution**. Once initialized, the queries operate on new events. Events that change the query result are sent to the client immediately. |
| |
| ## <a id="cq_api"></a>Typical Continuous Query Lifecycle |
| |
| 1. The client creates the CQ. This sets up everything for running the query and provides the client with a `CqQuery` object, but does not execute the CQ. At this point, the query is in a `STOPPED `state, ready to be closed or run. |
| 2. The client initiates the CQ with an API call to one of the `CqQuery execute*` methods. This puts the query into a `RUNNING` state on the client and on the server. The server remotely evaluates the query string, and optionally returns the results to the client. `CqQuery execute*` methods include: |
| - `CqQuery.execute()` |
| - `CqQuery.executeWithInitialResults()` |
| |
| 1. A CQ Listener waits for events. When it receives events, it takes action accordingly with the data in the CqEvent. |
| 3. The CQ is closed by a client call to `CqQuery.close`. This de-allocates all resources in use for the CQ on the client and server. At this point, the cycle could begin again with the creation of a new `CqQuery` instance. |
| |
| ## <a id="ExecutingACQ"></a>Executing a Continuous Query from the Client |
| |
| The essential steps to create and execute a continuous query are: |
| |
| 1. Create an instance of the `QueryService` class. If you are using the pool API (recommended), you should obtain the `QueryService` from the pool. |
| 1. Define a CQ Listener (a `CqListener`) to field events sent from the server. |
| 1. Use one of the `CqQuery execute*` methods to submit the query string to the cache server. |
| 1. The server remotely evaluates the query string, then monitors those results and notifies the client if they change. |
| 1. The client listens for changes that match the query predicate. |
| 1. Iterate through the returned objects. |
| 1. When finished, close down the continuous query. |
| |
| ### <a id="CppCQExample"></a>C++ Continuous Query Example |
| |
| These C++ code excerpts are from the `examples/cpp/continuousquery` example included in your client |
| distribution. See the example for full context. |
| |
| Following the steps listed above, |
| |
| 1. Create a query service: |
| |
| ``` |
| auto queryService = pool->getQueryService(); |
| ``` |
| |
| 1. Define a CqListener: |
| |
| ``` |
| class MyCqListener : public CqListener { |
| ``` |
| |
| 1. Create an instance of your CqListener and insert it into a CQ attributes object: |
| |
| ``` |
| CqAttributesFactory cqFactory; |
| |
| auto cqListener = std::make_shared<MyCqListener>(); |
| |
| cqFactory.addCqListener(cqListener); |
| auto cqAttributes = cqFactory.create(); |
| ``` |
| |
| 1. Create a Continuous Query using the query service and the CQ attributes: |
| |
| ``` |
| auto query = queryService->newCq( |
| "MyCq", "SELECT * FROM /custom_orders c WHERE c.quantity > 30", |
| cqAttributes); |
| ``` |
| |
| 1. Execute the query: |
| |
| ``` |
| query->execute(); |
| ``` |
| |
| 1. Wait for events and do something with them. |
| |
| ``` |
| /* Excerpt from the CqListener */ |
| |
| /* Determine Operation Type */ |
| switch (cqEvent.getQueryOperation()) { |
| case CqOperation::OP_TYPE_CREATE: |
| opStr = "CREATE"; |
| break; |
| case CqOperation::OP_TYPE_UPDATE: |
| opStr = "UPDATE"; |
| break; |
| case CqOperation::OP_TYPE_DESTROY: |
| opStr = "DESTROY"; |
| break; |
| default: |
| break; |
| } |
| |
| ... |
| |
| /* Take action based on OP Type */ |
| |
| ``` |
| |
| 1. When finished, close up shop. |
| |
| ``` |
| query->execute(); |
| |
| ... (respond to events as they arrive) |
| |
| query->stop(); |
| query->close(); |
| |
| cache.close(); |
| ``` |