/*
* 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.yardstick.cache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.affinity.Affinity;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.yardstick.IgniteAbstractBenchmark;
import org.yardstickframework.BenchmarkConfiguration;
import org.yardstickframework.BenchmarkUtils;
/**
* Abstract class for Ignite benchmarks which use cache.
*/
public abstract class IgniteCacheAbstractBenchmark<K, V> extends IgniteAbstractBenchmark {
/** Cache. */
protected IgniteCache<K, V> cache;
/** */
private ThreadLocal<ThreadRange> threadRange = new ThreadLocal<>();
/** */
private AtomicInteger threadIdx = new AtomicInteger();
/** {@inheritDoc} */
@Override public void setUp(BenchmarkConfiguration cfg) throws Exception {
super.setUp(cfg);
cache = cache();
BenchmarkUtils.println(cfg, "Benchmark setUp [name=" + getClass().getSimpleName() +
", cacheName="+ cache.getName() +
", cacheCfg=" + cache.getConfiguration(CacheConfiguration.class) + ']');
if (args.printPartitionStatistics()) {
Map<ClusterNode, T2<List<Integer>, List<Integer>>> parts = new HashMap<>();
for (ClusterNode node : ignite().cluster().nodes())
parts.put(node,
new T2<List<Integer>, List<Integer>>(new ArrayList<Integer>(), new ArrayList<Integer>()));
U.sleep(5000);
Affinity<Object> aff = ignite().affinity(cache.getName());
for (int p = 0; p < aff.partitions(); p++) {
Collection<ClusterNode> nodes = aff.mapPartitionToPrimaryAndBackups(p);
boolean primary = true;
for (ClusterNode node : nodes) {
if (primary) {
parts.get(node).get1().add(p);
primary = false;
}
else
parts.get(node).get2().add(p);
}
}
BenchmarkUtils.println(cfg, "Partition stats. [cacheName: "+ cache.getName() +", topVer: "
+ ignite().cluster().topologyVersion() + "]");
BenchmarkUtils.println(cfg, "(Node id, Number of Primary, Percent, Number of Backup, Percent, Total, Percent)");
for (Map.Entry<ClusterNode, T2<List<Integer>, List<Integer>>> e : parts.entrySet()) {
List<Integer> primary = e.getValue().get1();
List<Integer> backup = e.getValue().get2();
BenchmarkUtils.println(cfg, e.getKey().id() + " "
+ primary.size() + " " + primary.size() * 1. /aff.partitions() + " "
+ backup.size() + " "
+ backup.size() * 1. / (aff.partitions() * (args.backups() == 0 ? 1 : args.backups())) + " "
+ (primary.size() + backup.size()) + " "
+ (primary.size() + backup.size() * 1.) / (aff.partitions() * args.backups() + aff.partitions())
);
}
}
}
/**
* @return Range.
*/
protected final ThreadRange threadRange() {
ThreadRange r = threadRange.get();
if (r == null) {
if (args.keysPerThread()) {
int idx = threadIdx.getAndIncrement();
int keysPerThread = (int)(args.range() / (float)cfg.threads());
int min = keysPerThread * idx;
int max = min + keysPerThread;
r = new ThreadRange(min, max);
}
else
r = new ThreadRange(0, args.range());
BenchmarkUtils.println(cfg, "Initialized thread range [min=" + r.min + ", max=" + r.max + ']');
threadRange.set(r);
}
return r;
}
/**
* Each benchmark must determine which cache will be used.
*
* @return IgniteCache Cache to use.
*/
protected abstract IgniteCache<K, V> cache();
/**
*
*/
static class ThreadRange {
/** */
final int min;
/** */
final int max;
/** */
final ThreadLocalRandom rnd;
/**
* @param min Min.
* @param max Max.
*/
private ThreadRange(int min, int max) {
this.min = min;
this.max = max;
rnd = ThreadLocalRandom.current();
}
/**
* @return Next random key.
*/
int nextRandom() {
return rnd.nextInt(min, max);
}
}
}