/* * 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.loadtests.h2indexing; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import javax.cache.CacheException; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.Ignition; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cache.query.annotations.QuerySqlField; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller; /** * SQL query stress test. */ public class FetchingQueryCursorStressTest { /** Node count. */ private static final int NODE_CNT = 4; // Switch to 4 to see better throughput. /** Number of entries. */ private static final int ENTRIES_CNT = 10_000; /** Cache name. */ private static final String CACHE_NAME = "cache"; /** Thread count. */ private static final int THREAD_CNT = 16; /** Execution counter. */ private static final AtomicLong CNT = new AtomicLong(); /** Verbose mode. */ private static final boolean VERBOSE = false; /** */ private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(30); public static final AtomicReference<Exception> error = new AtomicReference<>(); /** * Entry point. */ public static void main(String[] args) throws Exception { List<Thread> threads = new ArrayList<>(THREAD_CNT + 1); try (Ignite ignite = start()) { IgniteCache<Integer, Person> cache = ignite.cache(CACHE_NAME); loadData(ignite, cache); System.out.println("Loaded data: " + cache.size()); for (int i = 0; i < THREAD_CNT; i++) threads.add(startDaemon("qry-exec-" + i, new QueryExecutor(cache, "Select * from Person"))); threads.add(startDaemon("printer", new ThroughputPrinter())); Thread.sleep(TIMEOUT); for (Thread t : threads) t.join(); if(error.get()!=null) throw error.get(); } finally { Ignition.stopAll(false); } } /** * Start daemon thread. * * @param name Name. * @param r Runnable. */ private static Thread startDaemon(String name, Runnable r) { Thread t = new Thread(r); t.setName(name); t.setDaemon(true); t.start(); return t; } /** * Load data into Ignite. * * @param ignite Ignite. * @param cache Cache. */ private static void loadData(Ignite ignite, IgniteCache<Integer, Person> cache) throws Exception { try (IgniteDataStreamer<Object, Object> str = ignite.dataStreamer(cache.getName())) { for (int id = 0; id < ENTRIES_CNT; id++) str.addData(id, new Person(id, "John" + id, "Doe")); } } /** * Start topology. * * @return Client node. */ private static Ignite start() { int i = 0; for (; i < NODE_CNT; i++) Ignition.start(config(i, false)); return Ignition.start(config(i, true)); } /** * Create configuration. * * @param idx Index. * @param client Client flag. * @return Configuration. */ @SuppressWarnings("unchecked") private static IgniteConfiguration config(int idx, boolean client) { IgniteConfiguration cfg = new IgniteConfiguration(); cfg.setIgniteInstanceName("grid-" + idx); cfg.setClientMode(client); CacheConfiguration ccfg = new CacheConfiguration(); ccfg.setName(CACHE_NAME); ccfg.setIndexedTypes(Integer.class, Person.class); cfg.setMarshaller(new OptimizedMarshaller()); cfg.setCacheConfiguration(ccfg); cfg.setLocalHost("127.0.0.1"); return cfg; } /** * */ private static class Person implements Serializable { /** */ private static final long serialVersionUID = 0L; /** */ @QuerySqlField private int id; /** */ @QuerySqlField private String firstName; /** */ @QuerySqlField private String lastName; public Person(int id, String firstName, String lastName) { this.id = id; this.firstName = firstName; this.lastName = lastName; } } /** * Query runner. */ private static class QueryExecutor implements Runnable { /** Cache. */ private final IgniteCache<Integer, Person> cache; /** */ private final String query; /** * Constructor. * * @param cache Cache. */ public QueryExecutor(IgniteCache<Integer, Person> cache, String query) { this.cache = cache; this.query = query; } /** {@inheritDoc} */ @SuppressWarnings("InfiniteLoopStatement") @Override public void run() { System.out.println("Executor started: " + Thread.currentThread().getName()); try { while (error.get()==null && !Thread.currentThread().isInterrupted()) { long start = System.nanoTime(); SqlFieldsQuery qry = new SqlFieldsQuery(query); // qry.setArgs((Object[]) argumentForQuery()); Set<Integer> extIds = new HashSet<>(); for (List<?> next : cache.query(qry)) extIds.add((Integer)next.get(0)); long dur = (System.nanoTime() - start) / 1_000_000; CNT.incrementAndGet(); if (VERBOSE) System.out.println("[extIds=" + extIds.size() + ", dur=" + dur + ']'); } } catch (CacheException ex){ error.compareAndSet(null, ex); } } } /** * Throughput printer. */ private static class ThroughputPrinter implements Runnable { /** {@inheritDoc} */ @SuppressWarnings("InfiniteLoopStatement") @Override public void run() { while (error.get()==null) { long before = CNT.get(); long beforeTime = System.currentTimeMillis(); try { Thread.sleep(2000L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } long after = CNT.get(); long afterTime = System.currentTimeMillis(); double res = 1000 * ((double)(after - before)) / (afterTime - beforeTime); System.out.println((long)res + " ops/sec"); } } } }