| /* |
| * 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.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import javax.cache.processor.MutableEntry; |
| import org.apache.ignite.Ignite; |
| import org.apache.ignite.IgniteCache; |
| import org.apache.ignite.binary.BinaryObject; |
| import org.apache.ignite.cache.CacheAtomicityMode; |
| import org.apache.ignite.cache.CacheEntryProcessor; |
| import org.apache.ignite.configuration.CacheConfiguration; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.internal.binary.BinaryMarshaller; |
| import org.apache.ignite.internal.util.typedef.internal.CU; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| |
| /** |
| * Test for value copy in entry processor. |
| */ |
| // Test fails due to incorrect handling of CacheConfiguration#getCopyOnRead() and |
| // CacheObjectContext#storeValue() properties. Heap storage should be redesigned in this ticket. |
| @Ignore("https://issues.apache.org/jira/browse/IGNITE-10420") |
| public class CacheEntryProcessorCopySelfTest extends GridCommonAbstractTest { |
| /** Old value. */ |
| private static final int OLD_VAL = 100; |
| |
| /** New value. */ |
| private static final int NEW_VAL = 200; |
| |
| /** Empty array. */ |
| private static final int[] EMPTY_ARR = new int[0]; |
| |
| /** Deserializations counter. */ |
| private static final AtomicInteger cnt = new AtomicInteger(); |
| |
| /** p2p enabled. */ |
| private boolean p2pEnabled; |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { |
| IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); |
| |
| cfg.setIncludeEventTypes(EMPTY_ARR); |
| |
| cfg.setPeerClassLoadingEnabled(p2pEnabled); |
| |
| return cfg; |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testMutableEntryWithP2PEnabled() throws Exception { |
| doTestMutableEntry(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testMutableEntryWithP2PDisabled() throws Exception { |
| doTestMutableEntry(false); |
| } |
| |
| /** |
| * |
| */ |
| private void doTestMutableEntry(boolean p2pEnabled) throws Exception { |
| this.p2pEnabled = p2pEnabled; |
| |
| Ignite grid = startGrid(); |
| |
| assertEquals(p2pEnabled, grid.configuration().isPeerClassLoadingEnabled()); |
| |
| try { |
| // One deserialization due to copyOnRead == true. |
| doTest(true, false, OLD_VAL, 1); |
| |
| // One deserialization due to copyOnRead == true. |
| // Additional deserialization in case p2p enabled and not BinaryMarshaller due to storeValue == true on update entry. |
| doTest(true, true, NEW_VAL, p2pEnabled && |
| !(grid.configuration().getMarshaller() instanceof BinaryMarshaller) ? 2 : 1); |
| |
| // No deserialization. |
| doTest(false, false, NEW_VAL, 0); |
| |
| // One deserialization due to storeValue == true. |
| doTest(false, true, NEW_VAL, 1); |
| } |
| finally { |
| stopAllGrids(); |
| } |
| } |
| |
| /** |
| * @param cpOnRead Copy on read. |
| * @param mutate Mutate. |
| * @param expVal Expected value. |
| * @param expCnt Expected deserializations count. |
| */ |
| @SuppressWarnings("unchecked") |
| private void doTest(boolean cpOnRead, final boolean mutate, int expVal, int expCnt) throws Exception { |
| |
| Ignite ignite = grid(); |
| |
| CacheConfiguration ccfg = defaultCacheConfiguration(); |
| ccfg.setAtomicityMode(CacheAtomicityMode.ATOMIC); |
| ccfg.setCopyOnRead(cpOnRead); |
| ccfg.setNearConfiguration(null); |
| |
| IgniteCache<Integer, Value> cache = null; |
| |
| try { |
| cache = ignite.createCache(ccfg); |
| |
| cache.put(0, new Value(OLD_VAL)); |
| |
| cache.get(0); |
| |
| cnt.set(0); |
| |
| cache.invoke(0, new CacheEntryProcessor<Integer, Value, Object>() { |
| @Override public Object process(MutableEntry<Integer, Value> entry, Object... args) { |
| Value val = entry.getValue(); |
| |
| val.i = NEW_VAL; |
| |
| if (mutate) |
| entry.setValue(val); |
| |
| return null; |
| } |
| }); |
| |
| GridCacheAdapter ca = (GridCacheAdapter)((IgniteCacheProxy)cache).internalProxy().delegate(); |
| |
| GridCacheEntryEx entry = ca.entryEx(0); |
| |
| entry.unswap(); |
| |
| CacheObject obj = entry.peekVisibleValue(); |
| |
| entry.touch(); |
| |
| int actCnt = cnt.get(); |
| |
| if (obj instanceof BinaryObject) |
| if (cpOnRead) |
| assertEquals(expVal, (int)((BinaryObject)obj).field("i")); |
| else |
| assertEquals(expVal, ((Value)U.field(obj, "obj")).i); |
| else { |
| if (storeValue(cache)) |
| assertEquals(expVal, U.<Value>field(obj, "val").i); |
| else |
| assertEquals(expVal, CU.<Value>value(obj, ((IgniteCacheProxy)cache).context(), false).i); |
| } |
| |
| assertEquals(expCnt, actCnt); |
| } |
| finally { |
| if (cache != null) |
| cache.destroy(); |
| } |
| } |
| |
| /** |
| * @param cache Cache. |
| */ |
| private static boolean storeValue(IgniteCache cache) { |
| return ((IgniteCacheProxy)cache).context().cacheObjectContext().storeValue(); |
| } |
| |
| /** |
| * |
| */ |
| private static class Value implements Externalizable { |
| /** */ |
| private int i; |
| |
| /** |
| * Default constructor (required by Externalizable). |
| */ |
| public Value() { |
| } |
| |
| /** |
| * @param i I. |
| */ |
| public Value(int i) { |
| this.i = i; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public void writeExternal(ObjectOutput out) throws IOException { |
| out.writeInt(i); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
| i = in.readInt(); |
| |
| cnt.incrementAndGet(); |
| } |
| } |
| } |