/* * 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.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.cache.Cache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.store.CacheStore; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiInClosure; import static javax.cache.Cache.Entry; /** * Test store. */ @SuppressWarnings({"TypeParameterExtendsFinalClass"}) public class GridCacheGenericTestStore<K, V> implements CacheStore<K, V> { /** Store. */ private final Map<K, V> map = new ConcurrentHashMap<>(); /** Last method called. */ private String lastMtd; /** */ private long ts = System.currentTimeMillis(); /** {@link #write(Entry)} method call counter .*/ private AtomicInteger putCnt = new AtomicInteger(); /** {@link #writeAll(Collection)} method call counter .*/ private AtomicInteger putAllCnt = new AtomicInteger(); /** {@link #delete(Object)} method call counter. */ private AtomicInteger rmvCnt = new AtomicInteger(); /** {@link #deleteAll(Collection)} method call counter. */ private AtomicInteger rmvAllCnt = new AtomicInteger(); /** Flag indicating if methods of this store should fail. */ private volatile boolean shouldFail; /** Configurable delay to simulate slow storage. */ private int operationDelay; /** * @return Underlying map. */ public Map<K, V> getMap() { return Collections.unmodifiableMap(map); } /** * Sets a flag indicating if methods of this class should fail with {@link IgniteCheckedException}. * * @param shouldFail {@code true} if should fail. */ public void setShouldFail(boolean shouldFail) { this.shouldFail = shouldFail; } /** * Sets delay that this store should wait on each operation. * * @param operationDelay If zero, no delay applied, positive value means * delay in milliseconds. */ public void setOperationDelay(int operationDelay) { assert operationDelay >= 0; this.operationDelay = operationDelay; } /** * * @return Last method called. */ public String getLastMethod() { return lastMtd; } /** * @return Last timestamp. */ public long getTimestamp() { return ts; } /** * @return Integer timestamp. */ public int getStart() { return Math.abs((int)ts); } /** * Sets last method to <tt>null</tt>. */ public void resetLastMethod() { lastMtd = null; } /** * Resets timestamp. */ public void resetTimestamp() { ts = System.currentTimeMillis(); } /** * Resets the store to initial state. */ public void reset() { lastMtd = null; map.clear(); putCnt.set(0); putAllCnt.set(0); rmvCnt.set(0); rmvAllCnt.set(0); ts = System.currentTimeMillis(); } /** * @return Count of {@link #write(Entry)} method calls since last reset. */ public int getPutCount() { return putCnt.get(); } /** * @return Count of {@link #writeAll(Collection)} method calls since last reset. */ public int getPutAllCount() { return putAllCnt.get(); } /** * @return Number of {@link #delete(Object)} method calls since last reset. */ public int getRemoveCount() { return rmvCnt.get(); } /** * @return Number of {@link #deleteAll(Collection)} method calls since last reset. */ public int getRemoveAllCount() { return rmvAllCnt.get(); } /** {@inheritDoc} */ @Override public V load(K key) { lastMtd = "load"; checkOperation(); return map.get(key); } /** {@inheritDoc} */ @Override public void loadCache(IgniteBiInClosure<K, V> clo, Object[] args) { lastMtd = "loadAllFull"; checkOperation(); } /** {@inheritDoc} */ @Override public Map<K, V> loadAll(Iterable<? extends K> keys) { lastMtd = "loadAll"; Map<K, V> loaded = new HashMap<>(); for (K key : keys) { V val = map.get(key); if (val != null) loaded.put(key, val); } checkOperation(); return loaded; } /** {@inheritDoc} */ @Override public void write(Cache.Entry<? extends K, ? extends V> e) { lastMtd = "put"; checkOperation(); map.put(e.getKey(), e.getValue()); putCnt.incrementAndGet(); } /** {@inheritDoc} */ @Override public void writeAll(Collection<Cache.Entry<? extends K, ? extends V>> entries) { lastMtd = "putAll"; checkOperation(); for (Cache.Entry<? extends K, ? extends V> e : entries) this.map.put(e.getKey(), e.getValue()); putAllCnt.incrementAndGet(); } /** {@inheritDoc} */ @Override public void delete(Object key) { lastMtd = "remove"; checkOperation(); map.remove(key); rmvCnt.incrementAndGet(); } /** {@inheritDoc} */ @Override public void deleteAll(Collection<?> keys) { lastMtd = "removeAll"; checkOperation(); for (Object key : keys) map.remove(key); rmvAllCnt.incrementAndGet(); } /** {@inheritDoc} */ @Override public void sessionEnd(boolean commit) { // No-op. } /** * Checks the flag and throws exception if it is set. Checks operation delay and sleeps * for specified amount of time, if needed. */ private void checkOperation() { if (shouldFail) throw new IgniteException("Store exception"); if (operationDelay > 0) { try { U.sleep(operationDelay); } catch(IgniteInterruptedCheckedException e) { throw new IgniteException(e); } } } }