/*
* 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.cache;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ThreadLocalRandom;
import javax.cache.expiry.Duration;
import javax.cache.expiry.ModifiedExpiryPolicy;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.CacheAtomicityMode;
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.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC;
/**
*
*/
public class CacheOperationsWithExpirationTest extends GridCommonAbstractTest {
/** */
private static final int KEYS = 10_000;
/**
* @param atomicityMode Atomicity mode.
* @param offheapMem Offheap memory size.
* @param idx Indexing enabled flag.
* @return Cache configuration.
*/
private CacheConfiguration<String, TestIndexedType> cacheConfiguration(CacheAtomicityMode atomicityMode,
long offheapMem,
boolean idx) {
CacheConfiguration<String, TestIndexedType> ccfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
ccfg.setAtomicityMode(atomicityMode);
ccfg.setBackups(1);
ccfg.setWriteSynchronizationMode(PRIMARY_SYNC);
ccfg.setStatisticsEnabled(true);
if (idx)
ccfg.setIndexedTypes(String.class, TestIndexedType.class);
return ccfg;
}
/** {@inheritDoc} */
@Override protected void beforeTestsStarted() throws Exception {
super.beforeTestsStarted();
startGrid(0);
}
/** {@inheritDoc} */
@Override protected void afterTestsStopped() throws Exception {
stopAllGrids();
super.afterTestsStopped();
}
/**
* @throws Exception If failed.
*/
public void testAtomicIndexEnabled() throws Exception {
concurrentPutGetRemoveExpireAndQuery(cacheConfiguration(ATOMIC, 0, true));
}
/**
* @throws Exception If failed.
*/
public void testAtomic() throws Exception {
concurrentPutGetRemoveExpireAndQuery(cacheConfiguration(ATOMIC, 0, false));
}
/**
* @param ccfg Cache configuration.
* @throws Exception If failed.
*/
private void concurrentPutGetRemoveExpireAndQuery(CacheConfiguration<String, TestIndexedType> ccfg)
throws Exception {
Ignite ignite = ignite(0);
final IgniteCache<String, TestIndexedType> cache = ignite.createCache(ccfg);
final boolean qryEnabled = !F.isEmpty(ccfg.getQueryEntities());
try {
final long stopTime = U.currentTimeMillis() + 30_000;
GridTestUtils.runMultiThreaded(new IgniteInClosure<Integer>() {
@Override public void apply(Integer idx) {
while (U.currentTimeMillis() < stopTime) {
if (!qryEnabled || idx % 2 == 0)
putGet(cache);
else
query(cache);
}
}
void putGet(IgniteCache<String, TestIndexedType> cache) {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
cache = cache.withExpiryPolicy(new ModifiedExpiryPolicy(
new Duration(MILLISECONDS, rnd.nextLong(100) + 1)));
for (int i = 0; i < KEYS; i++) {
String key = String.valueOf(rnd.nextInt(KEYS));
cache.put(key, testValue(rnd));
}
Set<String> s = new TreeSet<>();
for (int i = 0; i < 1000; i++) {
String key = String.valueOf(rnd.nextInt(KEYS));
s.add(key);
}
cache.getAll(s);
cache.removeAll(s);
}
void query(IgniteCache<String, TestIndexedType> cache) {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
String k = String.valueOf(rnd.nextInt(KEYS));
SqlFieldsQuery qry1;
if (rnd.nextBoolean()) {
qry1 = new SqlFieldsQuery("select _key, _val from TestIndexedType where key1=? and intVal=?");
qry1.setArgs(k, k);
}
else
qry1 = new SqlFieldsQuery("select _key, _val from TestIndexedType");
List res = cache.query(qry1).getAll();
assertNotNull(res);
}
}, 10, "test-thread");
}
finally {
ignite.destroyCache(cache.getName());
}
}
/**
* @param rnd Random.
* @return Test value.
*/
private TestIndexedType testValue(ThreadLocalRandom rnd) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < rnd.nextInt(100); i++)
builder.append("string");
return new TestIndexedType(rnd.nextInt(KEYS), builder.toString());
}
/**
*
*/
public enum EnumType1 {
/** */
TYPE1,
/** */
TYPE2,
/** */
TYPE3;
/** */
static final EnumType1[] vals = EnumType1.values();
}
/**
*
*/
public enum EnumType2 {
/** */
TYPE1,
/** */
TYPE2,
/** */
TYPE3,
/** */
TYPE4;
/** */
static final EnumType2[] vals = EnumType2.values();
}
/**
*
*/
public static class TestIndexedType implements Serializable {
/** */
private static final long serialVersionUID = 1L;
/** */
@QuerySqlField
private final String key;
/** */
@QuerySqlField(index = true)
private final String key1;
/** */
@QuerySqlField(index = true)
private final String key2;
/** */
@QuerySqlField(index = true)
private final String key3;
/** */
@QuerySqlField(index = true)
private final int intVal;
/** */
private final EnumType1 type1;
/** */
@QuerySqlField(index = true)
private final EnumType2 type2;
/** */
@QuerySqlField(index = true)
private final Date date1;
/** */
@QuerySqlField(index = true)
private final Date date2;
/** */
private final Byte byteVal1;
/** */
private final Byte byteVal2;
/**
* @param rnd Random value.
* @param strVal Random string value.
*/
public TestIndexedType(int rnd, String strVal) {
intVal = rnd;
key = String.valueOf(rnd);
key1 = key;
key2 = strVal;
key3 = strVal;
date1 = new Date(rnd);
date2 = new Date(U.currentTimeMillis());
type1 = EnumType1.vals[rnd % EnumType1.vals.length];
type2 = EnumType2.vals[rnd % EnumType2.vals.length];
byteVal1 = (byte)rnd;
byteVal2 = (byte)rnd;
}
}
}