/*
* 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.
*/
package org.apache.ignite.internal.processors.query;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.cache.Cache;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.cache.query.SpiQuery;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.managers.communication.GridIoManager;
import org.apache.ignite.internal.managers.communication.GridIoPolicy;
import org.apache.ignite.internal.processors.cache.CacheEntryImpl;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.lang.IgniteBiPredicate;
import org.apache.ignite.spi.IgniteSpiAdapter;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
import org.apache.ignite.spi.indexing.IndexingQueryFilter;
import org.apache.ignite.spi.indexing.IndexingSpi;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.jetbrains.annotations.Nullable;
/**
* Ensures that SQL queries are executed in a dedicated thread pool.
*/
public class IgniteQueryDedicatedPoolTest extends GridCommonAbstractTest {
/** IP finder. */
private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
/** Name of the cache for test */
private static final String CACHE_NAME = "query_pool_test";
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
super.beforeTest();
startGrid("server");
}
/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(gridName);
TcpDiscoverySpi spi = (TcpDiscoverySpi)cfg.getDiscoverySpi();
spi.setIpFinder(IP_FINDER);
CacheConfiguration<Integer, Integer> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
ccfg.setIndexedTypes(Integer.class, Integer.class);
ccfg.setIndexedTypes(Byte.class, Byte.class);
ccfg.setSqlFunctionClasses(IgniteQueryDedicatedPoolTest.class);
ccfg.setName(CACHE_NAME);
cfg.setCacheConfiguration(ccfg);
if ("client".equals(gridName))
cfg.setClientMode(true);
cfg.setIndexingSpi(new TestIndexingSpi());
return cfg;
}
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
super.afterTest();
stopAllGrids();
}
/**
* Tests that SQL queries are executed in dedicated pool
* @throws Exception If failed.
*/
public void testSqlQueryUsesDedicatedThreadPool() throws Exception {
try (Ignite client = startGrid("client")) {
IgniteCache<Integer, Integer> cache = client.cache(CACHE_NAME);
QueryCursor<List<?>> cursor = cache.query(new SqlFieldsQuery("select currentPolicy()"));
List<List<?>> result = cursor.getAll();
cursor.close();
assertEquals(1, result.size());
Byte plc = (Byte)result.get(0).get(0);
assert plc != null;
assert plc == GridIoPolicy.QUERY_POOL;
}
}
/**
* Tests that Scan queries are executed in dedicated pool
* @throws Exception If failed.
*/
public void testScanQueryUsesDedicatedThreadPool() throws Exception {
try (Ignite client = startGrid("client")) {
IgniteCache<Integer, Integer> cache = client.cache(CACHE_NAME);
cache.put(0, 0);
QueryCursor<Cache.Entry<Object, Object>> cursor = cache.query(
new ScanQuery<>(new IgniteBiPredicate<Object, Object>() {
@Override public boolean apply(Object o, Object o2) {
return F.eq(GridIoManager.currentPolicy(), GridIoPolicy.QUERY_POOL);
}
}));
assertEquals(1, cursor.getAll().size());
cursor.close();
}
}
/**
* Tests that SPI queries are executed in dedicated pool
* @throws Exception If failed.
*/
public void testSpiQueryUsesDedicatedThreadPool() throws Exception {
try (Ignite client = startGrid("client")) {
IgniteCache<Byte, Byte> cache = client.cache(CACHE_NAME);
for (byte b = 0; b < Byte.MAX_VALUE; ++b)
cache.put(b, b);
QueryCursor<Cache.Entry<Byte, Byte>> cursor = cache.query(new SpiQuery<Byte, Byte>());
List<Cache.Entry<Byte, Byte>> all = cursor.getAll();
assertEquals(1, all.size());
assertEquals(GridIoPolicy.QUERY_POOL, (byte)all.get(0).getValue());
cursor.close();
}
}
/**
* Custom SQL function to return current thread name from inside query executor
* @return Current IO policy
*/
@SuppressWarnings("unused")
@QuerySqlFunction(alias = "currentPolicy")
public static Byte currentPolicy() {
return GridIoManager.currentPolicy();
}
/**
* Indexing Spi implementation for test
*/
private static class TestIndexingSpi extends IgniteSpiAdapter implements IndexingSpi {
/** Index. */
private final SortedMap<Object, Object> idx = new TreeMap<>();
/** {@inheritDoc} */
@Override public void spiStart(@Nullable String gridName) {
// No-op.
}
/** {@inheritDoc} */
@Override public void spiStop() {
// No-op.
}
/** {@inheritDoc} */
@Override public Iterator<Cache.Entry<?, ?>> query(@Nullable String spaceName, Collection<Object> params,
@Nullable IndexingQueryFilter filters) {
return idx.containsKey(GridIoPolicy.QUERY_POOL) ?
Collections.<Cache.Entry<?, ?>>singletonList(
new CacheEntryImpl<>(GridIoPolicy.QUERY_POOL, GridIoPolicy.QUERY_POOL)).iterator()
: Collections.<Cache.Entry<?, ?>>emptyList().iterator();
}
/** {@inheritDoc} */
@Override public void store(@Nullable String spaceName, Object key, Object val, long expirationTime) {
idx.put(key, val);
}
/** {@inheritDoc} */
@Override public void remove(@Nullable String spaceName, Object key) {
// No-op.
}
}
}