/* * 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.geode; import org.apache.geode.cache.*; import org.apache.geode.cache.query.*; import org.apache.geode.cache.query.internal.index.IndexManager; import org.apache.geode.cache.util.CacheListenerAdapter; import org.apache.geode.cache.util.TransactionListenerAdapter; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.NanoTimer; import org.apache.geode.internal.cache.*; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.util.StopWatch; import org.apache.geode.test.junit.categories.IntegrationTest; import org.junit.*; import org.junit.experimental.categories.Category; import org.junit.rules.TestName; import javax.transaction.Synchronization; import java.util.*; import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; import static org.junit.Assert.*; /** * Tests basic transaction functionality * * @since GemFire 4.0 * */ @Category(IntegrationTest.class) public class TXJUnitTest { @Rule public TestName testName = new TestName(); private int cbCount; private TransactionEvent te; protected int listenerAfterCommit; protected int listenerAfterFailedCommit; protected int listenerAfterRollback; protected int listenerClose; protected CacheTransactionManager txMgr; protected GemFireCacheImpl cache; protected Region region; private boolean isPR() { return (this.region instanceof PartitionedRegion); } protected void createCache() throws Exception { Properties p = new Properties(); p.setProperty(MCAST_PORT, "0"); // loner this.cache = (GemFireCacheImpl) CacheFactory.create(DistributedSystem.connect(p)); createRegion(); this.txMgr = this.cache.getCacheTransactionManager(); this.listenerAfterCommit = 0; this.listenerAfterFailedCommit = 0; this.listenerAfterRollback = 0; this.listenerClose = 0; } /** * */ protected void createRegion() throws Exception { AttributesFactory af = new AttributesFactory(); af.setScope(Scope.DISTRIBUTED_NO_ACK); af.setConcurrencyChecksEnabled(false); // test validation expects this behavior af.setIndexMaintenanceSynchronous(true); this.region = this.cache.createRegion("TXJUnitTest", af.create()); } protected void closeCache() { if (this.cache != null) { if (this.txMgr != null) { try { this.txMgr.rollback(); } catch (IllegalStateException ignore) { } } this.region = null; this.txMgr = null; Cache c = this.cache; this.cache = null; c.close(); } } @Before public void setUp() throws Exception { createCache(); } @After public void tearDown() throws Exception { closeCache(); } @AfterClass public static void afterClass() { InternalDistributedSystem ids = InternalDistributedSystem.getAnyInstance(); if (ids != null) { ids.disconnect(); } } private void checkNoTxState() { assertEquals(null, this.txMgr.getTransactionId()); assertTrue(!this.txMgr.exists()); try { this.txMgr.commit(); fail("expected IllegalStateException"); } catch (CommitConflictException unexpected) { fail("did not expect " + unexpected); } catch (IllegalStateException expected) { } try { this.txMgr.rollback(); fail("expected IllegalStateException"); } catch (IllegalStateException expected) { } } @Test public void testSimpleOps() throws CacheException { final CachePerfStats stats = this.cache.getCachePerfStats(); // See if things are ok when no transaction checkNoTxState(); this.txMgr.begin(); // now that a transaction exists make sure things behave as expected assertTrue(this.txMgr.getTransactionId() != null); assertTrue(this.txMgr.exists()); try { this.txMgr.begin(); fail("expected IllegalStateException"); } catch (IllegalStateException expected) { } try { this.txMgr.commit(); } catch (CommitConflictException unexpected) { fail("did not expect " + unexpected); } checkNoTxState(); this.txMgr.begin(); this.txMgr.rollback(); checkNoTxState(); this.region.put("uaKey", "val"); { Region.Entry cmtre = this.region.getEntry("uaKey"); cmtre.setUserAttribute("uaValue1"); assertEquals("uaValue1", cmtre.getUserAttribute()); int txRollbackChanges = stats.getTxRollbackChanges(); int txCommitChanges = stats.getTxCommitChanges(); int txFailureChanges = stats.getTxFailureChanges(); this.txMgr.begin(); Region.Entry txre = this.region.getEntry("uaKey"); assertEquals(this.region, txre.getRegion()); if (isPR()) { this.region.put("1", "one"); try { txre.setUserAttribute("uaValue2"); } catch (UnsupportedOperationException e) { // expected } try { txre.getUserAttribute(); } catch (UnsupportedOperationException e) { // expected } } else { assertEquals("uaValue1", txre.getUserAttribute()); txre.setUserAttribute("uaValue2"); assertEquals("uaValue2", txre.getUserAttribute()); } this.txMgr.rollback(); try { txre.getValue(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.isDestroyed(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.getUserAttribute(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.setUserAttribute("foo"); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(txCommitChanges, stats.getTxCommitChanges()); assertEquals(txFailureChanges, stats.getTxFailureChanges()); assertEquals("uaValue1", cmtre.getUserAttribute()); } { int txRollbackChanges = stats.getTxRollbackChanges(); int txCommitChanges = stats.getTxCommitChanges(); int txFailureChanges = stats.getTxFailureChanges(); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.txMgr.rollback(); assertEquals(this.region.get("key1"), "value1"); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(txCommitChanges, stats.getTxCommitChanges()); assertEquals(txFailureChanges, stats.getTxFailureChanges()); txRollbackChanges = stats.getTxRollbackChanges(); this.txMgr.begin(); this.region.destroy("key1"); this.txMgr.rollback(); assertEquals(this.region.get("key1"), "value1"); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(txCommitChanges, stats.getTxCommitChanges()); assertEquals(txFailureChanges, stats.getTxFailureChanges()); txRollbackChanges = stats.getTxRollbackChanges(); this.txMgr.begin(); this.region.put("key1", "value2"); this.txMgr.rollback(); assertEquals(this.region.get("key1"), "value1"); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(txCommitChanges, stats.getTxCommitChanges()); assertEquals(txFailureChanges, stats.getTxFailureChanges()); } } @Test public void testWriteOps() throws CacheException { this.txMgr.begin(); this.region.put("key1", "value1"); this.region.put("key2", "value2"); assertTrue(this.region.containsKey("key1")); assertTrue(this.region.containsValueForKey("key1")); assertEquals("key1", this.region.getEntry("key1").getKey()); assertEquals("value1", this.region.getEntry("key1").getValue()); assertEquals("value1", this.region.get("key1")); assertTrue(this.region.containsKey("key2")); assertTrue(this.region.containsValueForKey("key2")); assertEquals("key2", this.region.getEntry("key2").getKey()); assertEquals("value2", this.region.getEntry("key2").getValue()); assertEquals("value2", this.region.get("key2")); this.txMgr.rollback(); assertTrue(!this.region.containsKey("key1")); assertTrue(!this.region.containsKey("key2")); this.txMgr.begin(); this.region.create("key1", "value1"); assertTrue(this.region.containsKey("key1")); assertTrue(this.region.containsValueForKey("key1")); assertEquals("key1", this.region.getEntry("key1").getKey()); assertEquals("value1", this.region.getEntry("key1").getValue()); assertEquals("value1", this.region.get("key1")); this.txMgr.rollback(); assertTrue(!this.region.containsKey("key1")); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.put("key1", "value2"); this.txMgr.rollback(); assertTrue(this.region.containsKey("key1")); assertEquals("value1", this.region.get("key1")); this.region.localDestroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.localDestroy("key1"); assertTrue(!this.region.containsKey("key1")); assertTrue(!this.region.containsValueForKey("key1")); this.txMgr.rollback(); assertTrue(this.region.containsKey("key1")); this.region.localDestroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.destroy("key1"); assertTrue(!this.region.containsKey("key1")); assertTrue(!this.region.containsValueForKey("key1")); this.txMgr.rollback(); assertTrue(this.region.containsKey("key1")); this.region.localDestroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); assertTrue(this.region.containsValueForKey("key1")); this.region.localInvalidate("key1"); assertTrue(this.region.containsKey("key1")); assertTrue(!this.region.containsValueForKey("key1")); assertEquals(null, this.region.get("key1")); this.txMgr.rollback(); assertTrue(this.region.containsValueForKey("key1")); this.region.localDestroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); assertTrue(this.region.containsValueForKey("key1")); this.region.invalidate("key1"); assertTrue(this.region.containsKey("key1")); assertTrue(!this.region.containsValueForKey("key1")); assertEquals(null, this.region.get("key1")); this.txMgr.rollback(); assertTrue(this.region.containsValueForKey("key1")); this.region.localDestroy("key1"); // see if commits work assertTrue(!this.region.containsKey("key1")); assertTrue(!this.region.containsKey("key2")); this.txMgr.begin(); this.region.create("key1", "value1"); this.region.create("key2", "value2"); this.txMgr.commit(); assertTrue(this.region.containsKey("key1")); assertTrue(this.region.containsValueForKey("key1")); assertEquals("key1", this.region.getEntry("key1").getKey()); assertEquals("value1", this.region.getEntry("key1").getValue()); assertEquals("value1", this.region.get("key1")); assertTrue(this.region.containsKey("key2")); assertTrue(this.region.containsValueForKey("key2")); assertEquals("key2", this.region.getEntry("key2").getKey()); assertEquals("value2", this.region.getEntry("key2").getValue()); assertEquals("value2", this.region.get("key2")); this.region.localDestroy("key1"); this.region.localDestroy("key2"); } @Test public void testTwoRegionTxs() throws CacheException { final CachePerfStats stats = this.cache.getCachePerfStats(); int txCommitChanges; TransactionId myTxId; AttributesFactory af = new AttributesFactory(); af.setScope(Scope.DISTRIBUTED_NO_ACK); Region reg1 = this.region; Region reg2 = this.cache.createRegion(getUniqueName(), af.create()); this.txMgr.setListener(new TransactionListener() { public void afterCommit(TransactionEvent event) { listenerAfterCommit = 1; te = event; } public void afterFailedCommit(TransactionEvent event) { listenerAfterFailedCommit = 1; te = event; } public void afterRollback(TransactionEvent event) { listenerAfterRollback = 1; te = event; } public void close() { listenerClose = 1; } }); // see if commits work txCommitChanges = stats.getTxCommitChanges(); assertTrue(!reg1.containsKey("key1")); assertTrue(!reg2.containsKey("key2")); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); reg2.create("key2", "value2"); this.txMgr.commit(); assertTrue(reg1.containsKey("key1")); assertTrue(reg1.containsValueForKey("key1")); assertEquals("key1", reg1.getEntry("key1").getKey()); assertEquals("value1", reg1.getEntry("key1").getValue()); assertEquals("value1", reg1.get("key1")); assertTrue(reg2.containsKey("key2")); assertTrue(reg2.containsValueForKey("key2")); assertEquals("key2", reg2.getEntry("key2").getKey()); assertEquals("value2", reg2.getEntry("key2").getValue()); assertEquals("value2", reg2.get("key2")); assertEquals(txCommitChanges + 2, stats.getTxCommitChanges()); { Collection creates = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(2, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1 || ev.getRegion() == reg2); if (ev.getRegion() == reg1) { assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); } else { assertEquals("key2", ev.getKey()); assertEquals("value2", ev.getNewValue()); } assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); reg2.localDestroy("key2"); reg2.localDestroyRegion(); } @Test public void testTxEvent() throws CacheException { TransactionId myTxId; Region reg1 = this.region; this.txMgr.setListener(new TransactionListener() { public void afterCommit(TransactionEvent event) { listenerAfterCommit = 1; te = event; } public void afterFailedCommit(TransactionEvent event) { listenerAfterFailedCommit = 1; te = event; } public void afterRollback(TransactionEvent event) { listenerAfterRollback = 1; te = event; } public void close() { listenerClose = 1; } }); // make sure each operation has the correct transaction event // check create this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check put of existing entry reg1.create("key1", "value0"); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getPutEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check put of non-existent entry this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value0"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value0", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check d invalidate of existing entry reg1.create("key1", "value0"); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check l invalidate of existing entry reg1.create("key1", "value0"); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); if (!isPR()) assertTrue(!ev.isDistributed()); } } reg1.localDestroy("key1"); // check d destroy of existing entry reg1.create("key1", "value0"); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.destroy("key1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check l destroy of existing entry reg1.create("key1", "value0"); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localDestroy("key1"); this.txMgr.rollback(); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); { Cache teCache = this.te.getCache(); assertEquals(teCache, this.cache); Collection creates = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, creates.size()); Iterator it = creates.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); if (!isPR()) assertTrue(!ev.isDistributed()); } } reg1.localDestroy("key1"); } private static class CountingCallBackValidator { ArrayList asserts; final String createWriterAssert = "create writer Assert"; final String createListenerAssert = "create listener Assert"; final String updateWriterAssert = "update writer Assert"; final String updateListenerAssert = "update listener Assert"; final String invalAssert = "invalidate Assert"; final String destroyWriterAssert = "destroy writer Assert"; final String destroyListenerAssert = "destroy listener Assert"; final String localDestroyWriterAssert = "local destroy writer Assert"; final String localDestroyListenerAssert = "local destroy listener Assert"; CountingCacheListener cl; CountingCacheWriter cw; CountingCallBackValidator(CountingCacheListener cl, CountingCacheWriter cw) { this.cl = cl; this.cw = cw; this.asserts = new ArrayList(8); } void assertCreateWriterCnt(int cnt) { assertCreateWriterCnt(cnt, true); } void assertCreateWriterCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(createWriterAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cw.getBeforeCreateCalls()); } void assertCreateListenerCnt(int cnt) { assertCreateListenerCnt(cnt, true); } void assertCreateListenerCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(createListenerAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cl.getAfterCreateCalls()); } void assertDestroyWriterCnt(int cnt) { assertDestroyWriterCnt(cnt, true); } void assertDestroyWriterCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(destroyWriterAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cw.getBeforeDestroyCalls(false)); } void assertDestroyListenerCnt(int cnt) { assertDestroyListenerCnt(cnt, true); } void assertDestroyListenerCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(destroyListenerAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cl.getAfterDestroyCalls(false)); } void assertLocalDestroyWriterCnt(int cnt) { assertLocalDestroyWriterCnt(cnt, true); } void assertLocalDestroyWriterCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(localDestroyWriterAssert); this.asserts.add(new Integer(cnt)); } assertEquals(0, this.cw.getBeforeDestroyCalls(true)); } void assertLocalDestroyListenerCnt(int cnt) { assertLocalDestroyListenerCnt(cnt, true); } void assertLocalDestroyListenerCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(localDestroyListenerAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cl.getAfterDestroyCalls(true)); } void assertUpdateWriterCnt(int cnt) { assertUpdateWriterCnt(cnt, true); } void assertUpdateWriterCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(updateWriterAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cw.getBeforeUpdateCalls()); } void assertUpdateListenerCnt(int cnt) { assertUpdateListenerCnt(cnt, true); } void assertUpdateListenerCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(updateListenerAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cl.getAfterUpdateCalls()); } void assertInvalidateCnt(int cnt) { assertInvalidateCnt(cnt, true); } void assertInvalidateCnt(int cnt, boolean remember) { if (remember) { this.asserts.add(invalAssert); this.asserts.add(new Integer(cnt)); } assertEquals(cnt, this.cl.getAfterInvalidateCalls()); } void reAssert() { Iterator assertItr = this.asserts.iterator(); String assertType; Integer count; int cnt; while (assertItr.hasNext()) { assertType = (String) assertItr.next(); assertTrue("CountingCallBackValidator reassert, did not have an associated count", assertItr.hasNext()); count = (Integer) assertItr.next(); cnt = count.intValue(); if (assertType.equals(createWriterAssert)) { this.assertCreateWriterCnt(cnt, false); } else if (assertType.equals(createListenerAssert)) { this.assertCreateListenerCnt(cnt, false); } else if (assertType.equals(updateWriterAssert)) { this.assertUpdateWriterCnt(cnt, false); } else if (assertType.equals(updateListenerAssert)) { this.assertUpdateListenerCnt(cnt, false); } else if (assertType.equals(invalAssert)) { this.assertInvalidateCnt(cnt, false); } else if (assertType.equals(destroyWriterAssert)) { this.assertDestroyWriterCnt(cnt, false); } else if (assertType.equals(destroyListenerAssert)) { this.assertDestroyListenerCnt(cnt, false); } else if (assertType.equals(localDestroyWriterAssert)) { this.assertLocalDestroyWriterCnt(cnt, false); } else if (assertType.equals(localDestroyListenerAssert)) { this.assertLocalDestroyListenerCnt(cnt, false); } else { fail("CountingCallBackValidator reassert, unknown type"); } } } void reset() { this.cl.reset(); this.cw.reset(); this.asserts.clear(); } } private static interface CountingCacheListener extends CacheListener { public int getAfterCreateCalls(); public int getAfterUpdateCalls(); public int getAfterInvalidateCalls(); public int getAfterDestroyCalls(boolean fetchLocal); public void reset(); } private static interface CountingCacheWriter extends CacheWriter { public int getBeforeCreateCalls(); public int getBeforeUpdateCalls(); public int getBeforeDestroyCalls(boolean fetchLocal); public void reset(); } @Test public void testTxAlgebra() throws CacheException { TransactionId myTxId; Region reg1 = this.region; this.txMgr.setListener(new TransactionListener() { public void afterCommit(TransactionEvent event) { listenerAfterCommit = 1; te = event; } public void afterFailedCommit(TransactionEvent event) { listenerAfterFailedCommit = 1; te = event; } public void afterRollback(TransactionEvent event) { listenerAfterRollback = 1; te = event; } public void close() { listenerClose = 1; } }); AttributesMutator mutator = this.region.getAttributesMutator(); CountingCacheListener cntListener = new CountingCacheListener() { volatile int aCreateCalls, aUpdateCalls, aInvalidateCalls, aDestroyCalls, aLocalDestroyCalls; public void close() {} public void reset() { this.aCreateCalls = this.aUpdateCalls = this.aInvalidateCalls = this.aDestroyCalls = this.aLocalDestroyCalls = 0; } public void afterCreate(EntryEvent e) { ++this.aCreateCalls; } public void afterUpdate(EntryEvent e) { ++this.aUpdateCalls; } public void afterInvalidate(EntryEvent e) { ++this.aInvalidateCalls; } public void afterDestroy(EntryEvent e) { if (e.isDistributed()) { ++this.aDestroyCalls; } else { ++this.aLocalDestroyCalls; } } public void afterRegionInvalidate(RegionEvent e) { fail("Unexpected afterRegionInvalidate in testTxAlgebra"); } public void afterRegionDestroy(RegionEvent e) { if (!e.getOperation().isClose()) { fail("Unexpected afterRegionDestroy in testTxAlgebra"); } } public void afterRegionClear(RegionEvent event) {} public void afterRegionCreate(RegionEvent event) {} public void afterRegionLive(RegionEvent event) {} public int getAfterCreateCalls() { return this.aCreateCalls; } public int getAfterUpdateCalls() { return this.aUpdateCalls; } public int getAfterInvalidateCalls() { return this.aInvalidateCalls; } public int getAfterDestroyCalls(boolean fetchLocal) { return fetchLocal ? this.aLocalDestroyCalls : this.aDestroyCalls; } }; mutator.setCacheListener(cntListener); CountingCacheWriter cntWriter = new CountingCacheWriter() { int bCreateCalls, bUpdateCalls, bDestroyCalls, bLocalDestroyCalls; public void close() {} public void reset() { this.bCreateCalls = this.bUpdateCalls = this.bDestroyCalls = this.bLocalDestroyCalls = 0; } public void beforeCreate(EntryEvent e) { ++this.bCreateCalls; } public void beforeUpdate(EntryEvent e) { ++this.bUpdateCalls; } public void beforeDestroy(EntryEvent e) { ++this.bDestroyCalls; } public void beforeRegionDestroy(RegionEvent e) { fail("Unexpected beforeRegionDestroy in testTxAlgebra"); } public void beforeRegionClear(RegionEvent e) { fail("Unexpected beforeRegionClear in testTxAlgebra"); } public int getBeforeCreateCalls() { return this.bCreateCalls; } public int getBeforeUpdateCalls() { return this.bUpdateCalls; } public int getBeforeDestroyCalls(boolean fetchLocal) { return fetchLocal ? this.bLocalDestroyCalls : this.bDestroyCalls; } }; mutator.setCacheWriter(cntWriter); CountingCallBackValidator callbackVal = new CountingCallBackValidator(cntListener, cntWriter); // make sure each op sequence has the correct affect transaction event // check C + C -> EX // check C + P -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); try { reg1.create("key1", "value2"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertCreateWriterCnt(1, /* remember */ false); reg1.put("key1", "value2"); callbackVal.assertUpdateWriterCnt(1); assertEquals("value2", reg1.getEntry("key1").getValue()); // Make sure listener callbacks were not triggered before commit callbackVal.assertCreateListenerCnt(0, false); callbackVal.assertUpdateListenerCnt(0); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.reAssert(); assertEquals("value2", reg1.getEntry("key1").getValue()); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value2", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // Check C + DI -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0, false); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); callbackVal.assertCreateListenerCnt(0, false); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); assertEquals(1, this.te.getEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // @todo mitch implement the following // check LI + DI -> NOOP // check DI + LI -> NOOP // check DI + DI -> NOOP // check LI + LI -> NOOP // check C + DD -> NOOP callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value0"); callbackVal.assertCreateWriterCnt(1); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); callbackVal.assertDestroyListenerCnt(0); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); // Check C + LI -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // Check C + LI + C -> EX // Check C + LI + P -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); try { reg1.create("key1", "ex"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertCreateWriterCnt(1, /* remember */ false); reg1.put("key1", "value2"); callbackVal.assertUpdateWriterCnt(1); assertTrue(reg1.containsKey("key1")); assertEquals("value2", reg1.getEntry("key1").getValue()); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertCreateListenerCnt(0, false); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertEquals("value2", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value2", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // Check C + LI + LD -> NOOP callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(0); callbackVal.assertDestroyListenerCnt(0); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getEvents().size()); // Check C + LI + DD -> NOOP callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getEvents().size()); // check C + LD -> NOOP callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value0"); callbackVal.assertCreateWriterCnt(1); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getEvents().size()); // check C + LD + D -> EX // check C + LD + I -> EX // check C + LD + C -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value0"); callbackVal.assertCreateWriterCnt(1, /* remember */ false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); try { reg1.localDestroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertLocalDestroyWriterCnt(1, /* remember */ false); try { reg1.destroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertDestroyWriterCnt(0); try { reg1.localInvalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0); try { reg1.invalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); reg1.create("key1", "value3"); callbackVal.assertCreateWriterCnt(2); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check C + LD + P -> C callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.create("key1", "value0"); callbackVal.assertCreateWriterCnt(1, /* remember */ false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.put("key1", "value3"); callbackVal.assertCreateWriterCnt(2); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(1); callbackVal.assertUpdateListenerCnt(0); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check put of existing entry // check P + C -> EX // check P + P -> P reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1, /* remember */ false); try { reg1.create("key1", "value2"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertUpdateWriterCnt(1, /* remember */ false); callbackVal.assertCreateWriterCnt(0); reg1.put("key1", "value3"); callbackVal.assertUpdateWriterCnt(2); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getPutEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check P + DI -> DI reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0, false); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); this.txMgr.commit(); callbackVal.assertInvalidateCnt(1); callbackVal.assertUpdateListenerCnt(0); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check P + DD -> D reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check P + LI -> LI reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); assertTrue(reg1.containsKey("key1")); assertTrue(!reg1.containsValueForKey("key1")); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertEquals(null, reg1.getEntry("key1").getValue()); assertTrue(!reg1.containsValueForKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } reg1.localDestroy("key1"); // Check P + LI + C -> EX // Check P + LI + P -> P reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1, /* remember */ false); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); try { reg1.create("key1", "ex"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertCreateWriterCnt(0); callbackVal.assertUpdateWriterCnt(1, /* remember */ false); reg1.put("key1", "value2"); callbackVal.assertUpdateWriterCnt(2); assertTrue(reg1.containsKey("key1")); assertEquals("value2", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertTrue(reg1.containsKey("key1")); assertEquals("value2", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getPutEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value2", ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // Check P + LI + LD -> LD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } // Check P + LI + DD -> DD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check P + LD -> LD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } // check P + LD + D -> EX // check P + LD + I -> EX // check P + LD + C -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); try { reg1.localDestroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertLocalDestroyWriterCnt(1, /* remember */ false); try { reg1.destroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertDestroyWriterCnt(0); try { reg1.localInvalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); try { reg1.invalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0); reg1.create("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check P + LD + P -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1, /* remember */ false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.put("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check DI + C -> EX // check DI + P -> P reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0); try { reg1.create("key1", "value1"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertCreateWriterCnt(0); reg1.put("key1", "value2"); callbackVal.assertUpdateWriterCnt(1); assertEquals("value2", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value2", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getPutEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value2", ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check DI + DD -> D reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check DI + LD -> LD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } // check DI + LD + D -> EX // check DI + LD + I -> EX // check DI + LD + C -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0, false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); try { reg1.localDestroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertLocalDestroyWriterCnt(1, /* remember */ false); try { reg1.destroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertDestroyWriterCnt(0); try { reg1.localInvalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); try { reg1.invalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); reg1.create("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check DI + LD + P -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.invalidate("key1", "value1"); callbackVal.assertInvalidateCnt(0, false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.put("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check LI + C -> EX // check LI + P -> P reg1.create("key1", "value0"); this.txMgr.begin(); callbackVal.reset(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0, false); try { reg1.create("key1", "value1"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } callbackVal.assertCreateWriterCnt(0); reg1.put("key1", "value2"); callbackVal.assertUpdateWriterCnt(1); assertEquals("value2", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(1); callbackVal.assertInvalidateCnt(0); callbackVal.reAssert(); assertEquals("value2", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getPutEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value2", ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check LI + DD -> DD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0, false); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check LI + LD -> LD reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0, false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertLocalDestroyListenerCnt(1); callbackVal.reAssert(); assertTrue(!reg1.containsKey("key1")); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getDestroyEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals(null, ev.getNewValue()); assertEquals("value0", ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } // check LI + LD + D -> EX // check LI + LD + I -> EX // check LI + LD + C -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0, false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); assertTrue(!reg1.containsKey("key1")); try { reg1.localDestroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertLocalDestroyWriterCnt(1, /* remember */ false); try { reg1.destroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertDestroyWriterCnt(0); try { reg1.localInvalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); try { reg1.invalidate("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException ok) { } callbackVal.assertInvalidateCnt(0, /* remember */ false); reg1.create("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check LI + LD + P -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localInvalidate("key1", "value1"); callbackVal.assertInvalidateCnt(0, false); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.put("key1", "value3"); callbackVal.assertCreateWriterCnt(1); assertEquals("value3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertInvalidateCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value3", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value3", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check init state LI + P + I -> I token (bug 33073) reg1.create("key1", "value0"); reg1.localInvalidate("key1"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); reg1.invalidate("key1"); callbackVal.assertInvalidateCnt(0, false); this.txMgr.commit(); callbackVal.assertUpdateListenerCnt(0); callbackVal.assertInvalidateCnt(1); callbackVal.reAssert(); assertNull(reg1.getEntry("key1").getValue()); { // Special check to assert Invaldate token LocalRegion.NonTXEntry nonTXe = (LocalRegion.NonTXEntry) reg1.getEntry("key1"); assertTrue(nonTXe.getRegionEntry().isInvalid()); } assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertNull(ev.getNewValue()); assertNull(ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } // check init state I + P + LI -> LI token (bug 33073) callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.put("key1", "value1"); callbackVal.assertUpdateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); reg1.localInvalidate("key1"); callbackVal.assertInvalidateCnt(0, false); this.txMgr.commit(); callbackVal.assertInvalidateCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.assertCreateListenerCnt(0); callbackVal.reAssert(); assertNull(reg1.getEntry("key1").getValue()); { // Special check to assert Local Invaldate token LocalRegion.NonTXEntry nonTXe = (LocalRegion.NonTXEntry) reg1.getEntry("key1"); assertTrue(nonTXe.getRegionEntry().isInvalid()); } assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getInvalidateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertNull(ev.getNewValue()); assertNull(ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(!ev.isDistributed()); } } reg1.localDestroy("key1"); // check DD + C -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value1", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check DD + P -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.destroy("key1"); callbackVal.assertDestroyWriterCnt(1); reg1.put("key1", "value1"); callbackVal.assertCreateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value1", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check LD + C -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.create("key1", "value1"); callbackVal.assertCreateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value1", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); // check LD + P -> C reg1.create("key1", "value0"); callbackVal.reset(); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); reg1.localDestroy("key1"); callbackVal.assertLocalDestroyWriterCnt(1); reg1.put("key1", "value1"); callbackVal.assertCreateWriterCnt(1); assertEquals("value1", reg1.getEntry("key1").getValue()); this.txMgr.commit(); callbackVal.assertLocalDestroyListenerCnt(0); callbackVal.assertCreateListenerCnt(0); callbackVal.assertUpdateListenerCnt(1); callbackVal.reAssert(); assertEquals("value1", reg1.getEntry("key1").getValue()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(1, this.te.getEvents().size()); { Collection events = this.te.getCreateEvents(); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(1, events.size()); Iterator it = events.iterator(); while (it.hasNext()) { EntryEvent ev = (EntryEvent) it.next(); assertEquals(myTxId, ev.getTransactionId()); assertTrue(ev.getRegion() == reg1); assertEquals("key1", ev.getKey()); assertEquals("value1", ev.getNewValue()); assertEquals(null, ev.getOldValue()); assertTrue(!ev.isLocalLoad()); assertTrue(!ev.isNetLoad()); assertTrue(!ev.isLoad()); assertTrue(!ev.isNetSearch()); assertEquals(null, ev.getCallbackArgument()); assertEquals(true, ev.isCallbackArgumentAvailable()); assertTrue(!ev.isOriginRemote()); assertTrue(!ev.isExpiration()); assertTrue(ev.isDistributed()); } } reg1.localDestroy("key1"); } private void doNonTxInvalidateRegionOp(CachePerfStats stats) throws Exception { int txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.region.create("key2", "value2"); this.txMgr.begin(); try { this.region.localInvalidateRegion(); fail("Should have gotten an UnsupportedOperationInTransactionException"); } catch (UnsupportedOperationInTransactionException ee) { // this is expected } this.txMgr.rollback(); assertEquals("value1", this.region.get("key1")); assertEquals("value2", this.region.get("key2")); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); this.region.put("key1", "value1"); this.region.put("key2", "value2"); this.txMgr.begin(); try { this.region.invalidateRegion(); fail("Should have gotten an UnsupportedOperationInTransactionException"); } catch (UnsupportedOperationInTransactionException ee) { // this is expected } this.txMgr.rollback(); assertEquals("value1", this.region.get("key1")); assertEquals("value2", this.region.get("key2")); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); } private void doNonTxDestroyRegionOp(CachePerfStats stats) throws Exception { int txRollbackChanges = stats.getTxRollbackChanges(); this.region.put("key1", "value1"); this.region.put("key2", "value2"); this.txMgr.begin(); try { this.region.localDestroyRegion(); fail("Should have gotten an UnsupportedOperationInTransactionException"); } catch (UnsupportedOperationInTransactionException ee) { // this is expected } this.txMgr.rollback(); assertTrue(!this.region.isDestroyed()); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); this.txMgr.begin(); try { this.region.destroyRegion(); fail("Should have gotten an UnsupportedOperationInTransactionException"); } catch (UnsupportedOperationInTransactionException ee) { // this is expected } this.txMgr.rollback(); assertTrue(!this.region.isDestroyed()); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); } @Test public void testNonTxRegionOps() throws Exception { final CachePerfStats stats = this.cache.getCachePerfStats(); doNonTxInvalidateRegionOp(stats); doNonTxDestroyRegionOp(stats); } @Test public void testEntryNotFound() { // make sure operations that should fail with EntryNotFoundException // do so when done transactionally try { try { this.region.destroy("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } try { this.region.localDestroy("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } try { this.region.invalidate("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } try { this.region.localInvalidate("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } this.txMgr.begin(); try { this.region.destroy("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } this.txMgr.rollback(); this.txMgr.begin(); try { this.region.localDestroy("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } this.txMgr.rollback(); this.txMgr.begin(); try { this.region.invalidate("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } this.txMgr.rollback(); this.txMgr.begin(); try { this.region.localInvalidate("noEntry"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } this.txMgr.rollback(); // check to see if EntryExistsException works in transactions this.region.create("key1", "value1"); try { this.region.create("key1", "value2"); fail("expected EntryExistsException"); } catch (EntryExistsException expected) { } this.txMgr.begin(); try { this.region.create("key1", "value2"); fail("expected EntryExistsException"); } catch (EntryExistsException expected) { } this.txMgr.rollback(); } catch (CacheException ex) { fail("unexpected " + ex); } } @Test public void testListener() { assertTrue(this.txMgr.getListener() == null); TransactionListener oldListener = this.txMgr.setListener(new TransactionListener() { public void afterCommit(TransactionEvent event) { listenerAfterCommit = 1; te = event; } public void afterFailedCommit(TransactionEvent event) { listenerAfterFailedCommit = 1; te = event; } public void afterRollback(TransactionEvent event) { listenerAfterRollback = 1; te = event; } public void close() { listenerClose = 1; } }); assertTrue(oldListener == null); this.txMgr.begin(); TransactionId myTxId = this.txMgr.getTransactionId(); assertEquals(0, this.listenerAfterRollback); this.txMgr.rollback(); assertEquals(1, this.listenerAfterRollback); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getEvents().size()); assertEquals(myTxId, this.te.getTransactionId()); this.txMgr.begin(); myTxId = this.txMgr.getTransactionId(); try { assertEquals(0, this.listenerAfterCommit); this.txMgr.commit(); } catch (CommitConflictException unexpected) { fail("did not expect " + unexpected); } assertEquals(1, this.listenerAfterCommit); assertEquals(0, this.te.getCreateEvents().size()); assertEquals(0, this.te.getPutEvents().size()); assertEquals(0, this.te.getInvalidateEvents().size()); assertEquals(0, this.te.getDestroyEvents().size()); assertEquals(0, this.te.getEvents().size()); assertEquals(myTxId, this.te.getTransactionId()); assertEquals(0, this.listenerClose); oldListener = this.txMgr.setListener(new TransactionListener() { public void afterCommit(TransactionEvent event) { listenerAfterCommit = 2; te = event; } public void afterFailedCommit(TransactionEvent event) { listenerAfterFailedCommit = 2; } public void afterRollback(TransactionEvent event) { listenerAfterRollback = 2; te = event; } public void close() { listenerClose = 2; } }); assertEquals(1, this.listenerClose); this.txMgr.begin(); assertEquals(1, this.listenerAfterRollback); this.txMgr.rollback(); assertEquals(2, this.listenerAfterRollback); this.txMgr.begin(); this.txMgr.setListener(oldListener); assertEquals(2, this.listenerClose); this.txMgr.rollback(); assertEquals(1, this.listenerAfterRollback); closeCache(); assertEquals(1, this.listenerClose); } // make sure standard Cache(Listener,Writer) // are not called during rollback @Test public void testNoCallbacksOnRollback() throws CacheException { // install listeners AttributesMutator mutator = this.region.getAttributesMutator(); mutator.setCacheListener(new CacheListenerAdapter() { public void close() { cbCount++; } public void afterCreate(EntryEvent event) { cbCount++; } public void afterUpdate(EntryEvent event) { cbCount++; } public void afterInvalidate(EntryEvent event) { cbCount++; } public void afterDestroy(EntryEvent event) { cbCount++; } public void afterRegionInvalidate(RegionEvent event) { cbCount++; } public void afterRegionDestroy(RegionEvent event) { cbCount++; } }); mutator.setCacheWriter(new CacheWriter() { public void close() { cbCount++; } public void beforeUpdate(EntryEvent event) throws CacheWriterException { cbCount++; } public void beforeCreate(EntryEvent event) throws CacheWriterException { cbCount++; } public void beforeDestroy(EntryEvent event) throws CacheWriterException { cbCount++; } public void beforeRegionDestroy(RegionEvent event) throws CacheWriterException { cbCount++; } public void beforeRegionClear(RegionEvent event) throws CacheWriterException { cbCount++; } }); this.txMgr.begin(); this.region.create("key1", "value1"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.cbCount = 0; this.region.create("key1", "value1"); // do a santify check to make sure callbacks are installed assertEquals(2, this.cbCount); // 2 -> 1writer + 1listener this.txMgr.begin(); this.region.put("key1", "value2"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.region.localDestroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.localDestroy("key1"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.region.put("key1", "value1"); this.txMgr.begin(); this.region.destroy("key1"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.region.put("key1", "value1"); this.txMgr.begin(); this.region.localInvalidate("key1"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.region.localDestroy("key1"); this.region.put("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.cbCount = 0; this.txMgr.rollback(); assertEquals(0, this.cbCount); this.region.localDestroy("key1"); } // // TXCallBackValidator is a container for holding state for validating Cache // callbacks // private class TXCallBackValidator { boolean passedValidation; boolean suspendValidation; int expectedCallCount; Object key; Object oldVal; boolean oldValIdentCheck; Object newVal; boolean newValIdentCheck; TransactionId txId; boolean isDistributed; boolean isLocalLoad; boolean isCreate; boolean isUpdate; boolean isDestroyed; boolean isInvalidate; Object callBackArg; // EntryEvent, CallCount validator for // callbacks (CacheWriter, CacheListener boolean validate(EntryEvent event, int cnt) { if (this.isSuspendValidation()) { return true; } this.passedValidation = false; assertEquals("Expected Call Count Assertion!", this.expectedCallCount, cnt); assertTrue(!event.isExpiration()); assertTrue(!event.isNetLoad()); assertEquals("isLoad Assertion!", this.isLoad(), event.isLoad()); assertEquals("isLocalLoad Assertion!", this.isLoad(), event.isLocalLoad()); assertTrue(!event.isNetSearch()); assertTrue(!event.isOriginRemote()); assertNotNull(event.getRegion()); assertNotNull(event.getRegion().getCache()); assertNotNull(event.getRegion().getCache().getCacheTransactionManager()); assertEquals(this.getTXId(), event.getTransactionId()); // assertIndexDetailsEquals(event.getTransactionId(), // event.getRegion().getCache().getCacheTransactionManager().getTransactionId(), ); if (!isPR()) assertEquals("IsDistributed Assertion!", this.isDistributed(), event.isDistributed()); assertEquals(this.getKey(), event.getKey()); assertSame(this.getCallBackArg(), event.getCallbackArgument()); if (newValIdentCheck) { assertSame(newVal, event.getNewValue()); } else { assertEquals(newVal, event.getNewValue()); } if (oldValIdentCheck) { assertSame(oldVal, event.getOldValue()); } else { assertEquals(oldVal, event.getOldValue()); } this.passedValidation = true; return true; } int setExpectedCount(int newVal) { int oldVal = this.expectedCallCount; this.expectedCallCount = newVal; return oldVal; } // int getCount() {return this.callCount;} // int setCount(int newVal) { // int oldVal = this.callCount; // this.callCount = newVal; // return oldVal; // } void setKey(Object key) { this.key = key; } Object getKey() { return this.key; } void setOldValue(Object val, boolean checkWithIdentity) { this.oldVal = val; this.oldValIdentCheck = checkWithIdentity; } Object getOldValue() { return this.oldVal; } void setNewValue(Object val, boolean checkWithIdentity) { this.newVal = val; this.newValIdentCheck = checkWithIdentity; } Object getNewValue() { return this.newVal; } TransactionId setTXId(TransactionId txId) { TransactionId old = this.txId; this.txId = txId; return old; } TransactionId getTXId() { return this.txId; } void setIsDistributed(boolean isDistributed) { this.isDistributed = isDistributed; } Object getCallBackArg() { return this.callBackArg; } void setCallBackArg(Object callBackArg) { this.callBackArg = callBackArg; } boolean isDistributed() { return this.isDistributed; } void setIsCreate(boolean isCreate) { this.isCreate = isCreate; } boolean isCreate() { return this.isCreate; } void setIsUpdate(boolean isUpdate) { this.isUpdate = isUpdate; } boolean isUpdate() { return this.isUpdate; } void setIsDestroy(boolean isDestroyed) { this.isDestroyed = isDestroyed; } boolean isDestroy() { return this.isDestroyed; } void setIsInvalidate(boolean isInvalidate) { this.isInvalidate = isInvalidate; } boolean isInvalidate() { return this.isInvalidate; } void setIsLoad(boolean isLoad) { this.isLocalLoad = isLoad; } boolean isLoad() { return this.isLocalLoad; } boolean suspendValidation(boolean toggle) { boolean oldVal = this.suspendValidation; this.suspendValidation = toggle; return oldVal; } boolean isSuspendValidation() { return this.suspendValidation; } void setPassedValidation(boolean passedValidation) { this.passedValidation = passedValidation; } boolean passedValidation() { return this.passedValidation; } } private static interface ValidatableCacheListener extends CacheListener { public void setValidator(TXCallBackValidator v); public void validate(); public void validateNoEvents(); public void reset(); public void setExpectedCount(int count); public int getCallCount(); } private static interface ValidatableCacheWriter extends CacheWriter { public void setValidator(TXCallBackValidator v); public int getCallCount(); public void localDestroyMakeup(int count); public void validate(); public void reset(); public void validateNoEvents(); } // Test to make sure CacheListener callbacks are called in place with // the CacheEvents properly constructed @Test public void testCacheCallbacks() throws CacheException { final String key1 = "Key1"; final String value1 = "value1"; final String value2 = "value2"; final String callBackArg = "call back arg"; // install listeners AttributesMutator mutator = this.region.getAttributesMutator(); TXCallBackValidator cbv = new TXCallBackValidator(); // Cache Listener ValidatableCacheListener vCl = new ValidatableCacheListener() { TXCallBackValidator v; int callCount; int prevCallCount; EntryEvent lastEvent; public void validate() { this.v.validate(this.lastEvent, this.callCount); } public void validate(EntryEvent event) { this.v.validate(event, ++this.callCount); } public void setValidator(TXCallBackValidator v) { this.v = v; } public void close() {} public void afterCreate(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } this.validate(event); this.v.setPassedValidation(false); assertTrue("IsCreate Assertion!", this.v.isCreate()); assertTrue(event.getRegion().containsKey(this.v.getKey())); assertTrue(event.getRegion().containsValueForKey(this.v.getKey())); assertNotNull(event.getRegion().getEntry(event.getKey()).getValue()); this.v.setPassedValidation(true); } public void afterUpdate(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsUpdate Assertion!", this.v.isUpdate()); assertTrue(event.getRegion().containsKey(this.v.getKey())); assertTrue(event.getRegion().containsValueForKey(this.v.getKey())); assertNotNull(event.getRegion().getEntry(event.getKey()).getValue()); this.v.setPassedValidation(true); } public void afterInvalidate(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsInvaldiate Assertion!", this.v.isInvalidate()); assertTrue(event.getRegion().containsKey(this.v.getKey())); assertTrue(!event.getRegion().containsValueForKey(this.v.getKey())); assertNull(event.getRegion().getEntry(event.getKey()).getValue()); this.v.setPassedValidation(true); } public void afterDestroy(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsDestroy Assertion!", this.v.isDestroy()); assertTrue(!event.getRegion().containsKey(this.v.getKey())); assertTrue(!event.getRegion().containsValueForKey(this.v.getKey())); assertNull(event.getRegion().getEntry(event.getKey())); this.v.setPassedValidation(true); } public void afterRegionInvalidate(RegionEvent event) { fail("Unexpected invokation of afterRegionInvalidate"); } public void afterRegionDestroy(RegionEvent event) { if (!event.getOperation().isClose()) { fail("Unexpected invokation of afterRegionDestroy"); } } public void afterRegionClear(RegionEvent event) { } public void afterRegionCreate(RegionEvent event) {} public void afterRegionLive(RegionEvent event) {} public void reset() { lastEvent = null; prevCallCount = callCount; } public void validateNoEvents() { assertNull("Did not expect listener callback", lastEvent); assertEquals(prevCallCount, callCount); } public void setExpectedCount(int count) { callCount = count; } public int getCallCount() { return callCount; } }; vCl.setValidator(cbv); mutator.setCacheListener(vCl); // CacheWriter ValidatableCacheWriter vCw = new ValidatableCacheWriter() { TXCallBackValidator v; int callCount; int prevCallCount; EntryEvent lastEvent; public int getCallCount() { return this.callCount; } public void localDestroyMakeup(int count) { this.callCount += count; } public void validate() { this.v.validate(this.lastEvent, this.callCount); } public void validate(EntryEvent event) { this.v.validate(event, ++this.callCount); } public void setValidator(TXCallBackValidator v) { this.v = v; } public void close() {} public void beforeCreate(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsCreate Assertion!", this.v.isCreate()); assertTrue(!event.getRegion().containsKey(this.v.getKey())); assertTrue(!event.getRegion().containsValueForKey(this.v.getKey())); assertNull(event.getRegion().getEntry(event.getKey())); this.v.setPassedValidation(true); } public void beforeUpdate(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsUpdate Assertion!", this.v.isUpdate()); assertTrue(event.getRegion().containsKey(this.v.getKey())); // Can not assert the following line, as the value being update may be invalide // assertTrue(event.getRegion().containsValueForKey(this.v.getKey())); this.v.setPassedValidation(true); } public void beforeDestroy(EntryEvent event) { lastEvent = event; if (this.v.isSuspendValidation()) { return; } validate(event); this.v.setPassedValidation(false); assertTrue("IsDestroy Assertion!", this.v.isDestroy()); assertTrue(event.getRegion().containsKey(this.v.getKey())); this.v.setPassedValidation(true); } public void beforeRegionDestroy(RegionEvent event) { fail("Unexpected invocation of beforeRegionDestroy"); } public void beforeRegionClear(RegionEvent event) { fail("Unexpected invocation of beforeRegionClear"); } public void reset() { lastEvent = null; prevCallCount = callCount; } public void validateNoEvents() { assertNull("Did not expect a writer event", lastEvent); assertEquals(prevCallCount, callCount); } }; vCw.setValidator(cbv); mutator.setCacheWriter(vCw); // Cache Loader mutator.setCacheLoader(new CacheLoader() { int count = 0; public Object load(LoaderHelper helper) throws CacheLoaderException { return new Integer(count++); } public void close() {} }); // Use this to track the number of callout method invocations int appCallCount = 1; // Create => beforeCreate/afterCreate tests cbv.setKey(key1); cbv.setCallBackArg(callBackArg); cbv.setNewValue(value1, false); cbv.setOldValue(null, true); cbv.setIsDistributed(true); cbv.setIsLoad(false); cbv.setIsCreate(true); cbv.setIsUpdate(false); // Test non-transactional create expecting beforeCreate/afterCreate call cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.create(key1, value1, callBackArg); assertTrue("Non-TX Create Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.localDestroy(key1); cbv.suspendValidation(false); // Test transactional create expecting afterCreate call this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.create(key1, value1, callBackArg); this.txMgr.commit(); assertTrue("TX Create Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.localDestroy(key1); // Put => afterCreate tests cbv.suspendValidation(false); cbv.setNewValue(value2, false); cbv.setOldValue(null, true); cbv.setIsDistributed(true); cbv.setIsLoad(false); cbv.setIsCreate(true); cbv.setIsUpdate(false); // Test non-transactional put expecting afterCreate call due to no // previous Entry cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.put(key1, value2, callBackArg); assertTrue("Non-TX Put->Create Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.localDestroy(key1); cbv.suspendValidation(false); // Test transactional put expecting afterCreate call due to no // previous Entry this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.put(key1, value2, callBackArg); this.txMgr.commit(); assertTrue("TX Put->Create Validation Assertion", cbv.passedValidation()); // Put => afterUpdate tests cbv.setNewValue(value1, false); cbv.setOldValue(value2, false); cbv.setIsDistributed(true); cbv.setIsLoad(false); cbv.setIsCreate(false); cbv.setIsUpdate(true); // Test non-transactional put expecting afterUpdate call due to // previous Entry cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.put(key1, value1, callBackArg); assertTrue("Non-TX Put->Update Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.localDestroy(key1); this.region.put(key1, value2); cbv.suspendValidation(false); // Test transactional put expecting afterUpdate call due to // previous Entry this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.put(key1, value1, callBackArg); this.txMgr.commit(); assertTrue("TX Put->Update Validation Assertion", cbv.passedValidation()); // LocalDestroy => afterDestroy, non-distributed tests cbv.setNewValue(null, true); cbv.setOldValue(value1, false); cbv.setIsDistributed(false); cbv.setIsLoad(false); cbv.setIsDestroy(true); cbv.setIsUpdate(false); // Test non-transactional localDestroy, expecting afterDestroy, // non-distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.localDestroy(key1, callBackArg); if (!isPR()) vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called assertTrue("Non-TX LocalDestroy Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.create(key1, value1); cbv.suspendValidation(false); // Test transactional localDestroy expecting afterDestroy, // non-distributed this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.localDestroy(key1, callBackArg); if (!isPR()) vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called this.txMgr.commit(); assertTrue("TX LocalDestroy Validation Assertion", cbv.passedValidation()); // Destroy => afterDestroy, distributed tests cbv.setNewValue(null, true); cbv.setOldValue(value1, false); cbv.setIsDistributed(true); cbv.setIsLoad(false); cbv.setIsDestroy(true); cbv.suspendValidation(true); this.region.create(key1, value1); cbv.suspendValidation(false); // Test non-transactional Destroy, expecting afterDestroy, // distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.destroy(key1, callBackArg); assertTrue("Non-TX Destroy Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.create(key1, value1); cbv.suspendValidation(false); // Test transactional Destroy, expecting afterDestroy, // distributed this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.destroy(key1, callBackArg); this.txMgr.commit(); assertTrue("TX Destroy Validation Assertion", cbv.passedValidation()); // localInvalidate => afterInvalidate, non-distributed tests cbv.setNewValue(null, true); cbv.setOldValue(value1, false); cbv.setIsDistributed(false); cbv.setIsLoad(false); cbv.setIsInvalidate(true); cbv.setIsDestroy(false); cbv.suspendValidation(true); this.region.create(key1, value1); cbv.suspendValidation(false); // Test non-transactional localInvalidate, expecting afterInvalidate // non-distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.localInvalidate(key1, callBackArg); assertTrue("Non-TX LocalInvalidate Validation Assertion", cbv.passedValidation()); vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called cbv.suspendValidation(true); this.region.put(key1, value1); cbv.suspendValidation(false); // Test transactional localInvalidate, expecting afterInvalidate // non-distributed this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.localInvalidate(key1, callBackArg); this.txMgr.commit(); assertTrue("TX LocalInvalidate Validation Assertion", cbv.passedValidation()); vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called cbv.suspendValidation(true); this.region.localDestroy(key1); // Invalidate => afterInvalidate, distributed tests cbv.setNewValue(null, true); cbv.setOldValue(value1, false); cbv.setIsDistributed(true); cbv.setIsLoad(false); cbv.suspendValidation(true); this.region.create(key1, value1); cbv.suspendValidation(false); // Test non-transactional Invalidate, expecting afterInvalidate // distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.invalidate(key1, callBackArg); vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called assertTrue("Non-TX Invalidate Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.put(key1, value1); cbv.suspendValidation(false); // Test transactional Invalidate, expecting afterInvalidate // distributed this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.invalidate(key1, callBackArg); this.txMgr.commit(); vCw.localDestroyMakeup(1); // Account for cacheWriter not begin called assertTrue("TX Invalidate Validation Assertion", cbv.passedValidation()); cbv.suspendValidation(true); this.region.localDestroy(key1); cbv.suspendValidation(false); // Create load Event tests int loaderValCheck = 0; cbv.setNewValue(new Integer(loaderValCheck++), false); cbv.setCallBackArg(null); cbv.setOldValue(null, false); cbv.setIsDistributed(true); cbv.setIsCreate(true); cbv.setIsUpdate(false); cbv.setIsLoad(true); // Test non-transactional load, expecting afterCreate distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.get(key1); assertTrue("Non-TX Invalidate Validation Assertion", cbv.passedValidation()); vCl.validate(); vCw.validate(); cbv.suspendValidation(true); this.region.localDestroy(key1); cbv.suspendValidation(false); // Test transactional load, expecting afterCreate distributed vCl.reset(); this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setNewValue(new Integer(loaderValCheck++), false); cbv.setExpectedCount(appCallCount++); this.region.get(key1); this.txMgr.rollback(); assertTrue("TX Invalidate Validation Assertion", cbv.passedValidation()); vCw.validate(); vCl.validateNoEvents(); vCl.setExpectedCount(vCl.getCallCount() + 1); this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setNewValue(new Integer(loaderValCheck++), false); cbv.setExpectedCount(appCallCount++); this.region.get(key1); vCw.validate(); vCw.reset(); this.txMgr.commit(); vCw.validateNoEvents(); assertTrue("TX Invalidate Validation Assertion", cbv.passedValidation()); vCl.validate(); cbv.suspendValidation(true); this.region.localDestroy(key1); cbv.suspendValidation(false); // Update load Event tests cbv.suspendValidation(true); this.region.create(key1, null); cbv.suspendValidation(false); assertTrue(this.region.containsKey(key1)); assertTrue(!this.region.containsValueForKey(key1)); cbv.setNewValue(new Integer(loaderValCheck++), false); cbv.setOldValue(null, false); cbv.setIsDistributed(true); cbv.setCallBackArg(null); cbv.setIsCreate(false); cbv.setIsUpdate(true); cbv.setIsLoad(true); // Test non-transactional load, expecting afterUpdate distributed cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); this.region.get(key1); assertTrue("Non-TX Invalidate Validation Assertion", cbv.passedValidation()); vCw.validate(); vCl.validate(); cbv.suspendValidation(true); this.region.invalidate(key1); cbv.suspendValidation(false); assertTrue(this.region.containsKey(key1)); assertTrue(!this.region.containsValueForKey(key1)); // Test transactional load, expecting afterUpdate distributed this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); cbv.setNewValue(new Integer(loaderValCheck++), false); this.region.get(key1); vCw.validate(); vCw.reset(); this.txMgr.commit(); vCw.validateNoEvents(); vCl.validate(); cbv.suspendValidation(true); this.region.invalidate(key1); cbv.suspendValidation(false); vCl.reset(); this.txMgr.begin(); cbv.setTXId(txMgr.getTransactionId()); cbv.setExpectedCount(appCallCount++); cbv.setNewValue(new Integer(loaderValCheck++), false); this.region.get(key1); this.txMgr.rollback(); assertTrue("TX Invalidate Validation Assertion", cbv.passedValidation()); vCw.validate(); vCl.validateNoEvents(); } @Test public void testEntryCount() throws CacheException { LocalRegion reg1 = (LocalRegion) this.region; assertEquals(0, reg1.entryCount()); reg1.create("key1", "value1"); assertEquals(1, reg1.entryCount()); reg1.create("key2", "value2"); assertEquals(2, reg1.entryCount()); reg1.localDestroy("key2"); assertEquals(1, reg1.entryCount()); reg1.create("key3", "value3"); assertEquals(2, reg1.entryCount()); this.txMgr.begin(); this.region.create("key2", "value2"); assertEquals(3, reg1.entryCount()); reg1.localDestroy("key2"); assertEquals(2, reg1.entryCount()); this.region.create("key2", "value2"); assertEquals(3, reg1.entryCount()); reg1.destroy("key2"); assertEquals(2, reg1.entryCount()); reg1.localInvalidate("key1"); assertEquals(2, reg1.entryCount()); reg1.put("key1", "value2"); assertEquals(2, reg1.entryCount()); this.region.create("key2", "value2"); assertEquals(3, reg1.entryCount()); reg1.localDestroy("key3"); assertEquals(2, reg1.entryCount()); reg1.create("key3", "value3"); assertEquals(3, reg1.entryCount()); this.txMgr.rollback(); assertEquals(2, reg1.entryCount()); } private void checkCollectionSize(int expectedSize) { checkCollectionSize(expectedSize, expectedSize, expectedSize); } private void checkCollectionSize(int expectedSize, int expectedRecSize) { checkCollectionSize(expectedSize, expectedRecSize, expectedSize); } private void checkCollectionSize(int expectedSize, int expectedRecSize, int expectedValuesSize) { int size = 0; for (Object key : this.region.entrySet(false)) { size++; } assertEquals(expectedSize, size); assertEquals(expectedSize, this.region.keySet().size()); assertEquals(expectedValuesSize, this.region.values().size()); assertEquals(expectedSize, this.region.entrySet(false).size()); assertEquals(expectedRecSize, this.region.entrySet(true).size()); } @Test public void testCollections() throws CacheException { Region reg1 = this.region; checkSubRegionCollecection(reg1); { Collection nonTxKeys = reg1.keySet(); Collection nonTxValues = reg1.values(); this.txMgr.begin(); reg1.create("key1", "value1"); Collection txKeys = reg1.keySet(); Collection txValues = reg1.values(); /* * [sumedh] No longer fail this scenario to avoid the overhead of ThreadLocal lookup in every * iteration. Besides does not look to be a harmful usage in any case. */ try { nonTxKeys.size(); fail(); } catch (IllegalStateException expected) { TransactionId txid = this.txMgr.getTransactionId(); assertEquals( LocalizedStrings.LocalRegion_NON_TRANSACTIONAL_REGION_COLLECTION_IS_BEING_USED_IN_A_TRANSACTION .toLocalizedString(txid), expected.getMessage()); } assertEquals(1, txKeys.size()); try { nonTxValues.size(); fail(); } catch (IllegalStateException expected) { TransactionId txid = this.txMgr.getTransactionId(); assertEquals( LocalizedStrings.LocalRegion_NON_TRANSACTIONAL_REGION_COLLECTION_IS_BEING_USED_IN_A_TRANSACTION .toLocalizedString(txid), expected.getMessage()); } assertEquals(1, txValues.size()); assertTrue(txKeys.contains("key1")); { Iterator txIt = txKeys.iterator(); assertTrue(txIt.hasNext()); assertTrue(txIt.hasNext()); assertEquals("key1", txIt.next()); assertTrue(!txIt.hasNext()); } assertTrue(txValues.contains("value1")); { Iterator txIt = txValues.iterator(); assertTrue(txIt.hasNext()); assertTrue(txIt.hasNext()); assertEquals("value1", txIt.next()); assertTrue(!txIt.hasNext()); } reg1.invalidate("key1"); // assertIndexDetailsEquals(0, nonTxKeys.size()); assertEquals(1, txKeys.size()); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(0, txValues.size()); assertTrue(txKeys.contains("key1")); assertTrue(!txValues.contains("value1")); reg1.create("key2", "value2"); reg1.create("key3", "value3"); // assertIndexDetailsEquals(0, nonTxKeys.size()); assertEquals(3, txKeys.size()); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(2, txValues.size()); reg1.put("key1", "value1"); // assertIndexDetailsEquals(0, nonTxKeys.size()); assertEquals(3, txKeys.size()); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(3, txValues.size()); reg1.localInvalidate("key2"); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(2, txValues.size()); reg1.invalidate("key1"); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(1, txValues.size()); reg1.destroy("key2"); reg1.destroy("key3"); assertEquals(1, txKeys.size()); reg1.destroy("key1"); assertEquals(0, txKeys.size()); assertTrue(!txKeys.contains("key1")); Iterator txIt = txKeys.iterator(); assertTrue(!txIt.hasNext()); this.txMgr.rollback(); try { txKeys.size(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txKeys.isEmpty(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txKeys.contains("key1"); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txKeys.iterator(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } txIt.hasNext(); } { // Collection nonTxValues = reg1.values(); this.txMgr.begin(); reg1.create("key1", "value1"); Collection txValues = reg1.values(); // assertIndexDetailsEquals(0, nonTxValues.size()); assertEquals(1, txValues.size()); assertTrue(txValues.contains("value1")); { Iterator txIt = txValues.iterator(); assertTrue(txIt.hasNext()); assertEquals("value1", txIt.next()); assertTrue(!txIt.hasNext()); } reg1.destroy("key1"); assertEquals(0, txValues.size()); assertTrue(!txValues.contains("value1")); assertTrue(!txValues.iterator().hasNext()); assertTrue(!txValues.iterator().hasNext()); this.txMgr.rollback(); } { Collection nonTxEntries = reg1.entrySet(false); this.txMgr.begin(); reg1.create("key1", "value1"); Collection txEntries = reg1.entrySet(false); // non-TX collections can now be used in a transactional context try { nonTxEntries.size(); fail(); } catch (IllegalStateException expected) { TransactionId txid = this.txMgr.getTransactionId(); assertEquals( LocalizedStrings.LocalRegion_NON_TRANSACTIONAL_REGION_COLLECTION_IS_BEING_USED_IN_A_TRANSACTION .toLocalizedString(txid), expected.getMessage()); } assertEquals(1, txEntries.size()); assertTrue(txEntries.contains(reg1.getEntry("key1"))); { Iterator txIt = txEntries.iterator(); assertTrue(txIt.hasNext()); assertTrue(txIt.hasNext()); assertEquals(reg1.getEntry("key1"), txIt.next()); assertTrue(!txIt.hasNext()); assertTrue(!txIt.hasNext()); } reg1.destroy("key1"); assertEquals(0, txEntries.size()); assertTrue(!txEntries.iterator().hasNext()); this.txMgr.rollback(); } { Collection nonTxKeys = reg1.keySet(); Collection nonTxValues = reg1.values(); assertEquals(0, nonTxKeys.size()); assertEquals(0, nonTxValues.size()); reg1.create("key1", "value1"); assertEquals(1, nonTxKeys.size()); assertEquals(1, nonTxValues.size()); reg1.invalidate("key1"); assertEquals(1, nonTxKeys.size()); assertEquals(0, nonTxValues.size()); this.txMgr.begin(); Collection txKeys = reg1.keySet(); Collection txValues = reg1.values(); assertEquals(1, txKeys.size()); assertEquals(0, txValues.size()); reg1.put("key1", "txValue1"); assertEquals(1, txKeys.size()); assertEquals(1, txValues.size()); assertTrue(txValues.iterator().hasNext()); assertEquals("txValue1", txValues.iterator().next()); // assertIndexDetailsEquals(0, nonTxValues.size()); // non-TX collections can now be used in a transactional context try { nonTxValues.iterator().hasNext(); } catch (IllegalStateException expected) { TransactionId txid = this.txMgr.getTransactionId(); assertEquals( LocalizedStrings.LocalRegion_NON_TRANSACTIONAL_REGION_COLLECTION_IS_BEING_USED_IN_A_TRANSACTION .toLocalizedString(txid), expected.getMessage()); } reg1.localInvalidate("key1"); assertEquals(0, txValues.size()); assertTrue(!txValues.iterator().hasNext()); this.txMgr.rollback(); } } /** * @param reg1 */ protected void checkSubRegionCollecection(Region reg1) { AttributesFactory af = new AttributesFactory(); af.setScope(Scope.DISTRIBUTED_NO_ACK); Region sub1 = this.region.createSubregion("collectionSub1", af.create()); af = new AttributesFactory(); Region sub2 = this.region.createSubregion("collectionSub2", af.create()); af = new AttributesFactory(); af.setScope(Scope.LOCAL); Region sub2_1 = sub2.createSubregion("collectionSub2_1", af.create()); checkCollectionSize(0); try { this.region.keySet().iterator().next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } try { this.region.values().iterator().next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } try { this.region.entrySet().iterator().next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } reg1.create("key1", "value1"); checkCollectionSize(1); { Iterator it = this.region.keySet().iterator(); it.next(); try { it.next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } } { Iterator it = this.region.values().iterator(); it.next(); try { it.next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } } { Iterator it = this.region.entrySet().iterator(); it.next(); try { it.next(); fail(); } catch (NoSuchElementException expected) { assertNull(expected.getMessage()); } } reg1.create("key2", "value2"); checkCollectionSize(2); reg1.localInvalidate("key2"); checkCollectionSize(2, 2, 1); reg1.localInvalidate("key1"); checkCollectionSize(2, 2, 0); reg1.localDestroy("key2"); checkCollectionSize(1, 1, 0); reg1.localDestroy("key1"); checkCollectionSize(0); // Non-TX recursive checks sub2_1.create("key6", "value6"); checkCollectionSize(0, 1); assertEquals(0, sub2.entrySet(false).size()); assertEquals(1, sub2.entrySet(true).size()); assertEquals(1, sub2_1.entrySet(true).size()); sub2.create("key5", "value5"); checkCollectionSize(0, 2); assertEquals(1, sub2.entrySet(false).size()); assertEquals(2, sub2.entrySet(true).size()); sub1.create("key4", "value4"); checkCollectionSize(0, 3); assertEquals(1, sub1.entrySet(false).size()); assertEquals(1, sub1.entrySet(true).size()); reg1.put("key1", "value1"); checkCollectionSize(1, 4); sub2.localDestroy("key5"); checkCollectionSize(1, 3); assertEquals(0, sub2.entrySet(false).size()); assertEquals(1, sub2.entrySet(true).size()); assertEquals(1, sub2_1.entrySet(false).size()); assertEquals(1, sub2_1.entrySet(true).size()); sub2_1.localDestroy("key6"); checkCollectionSize(1, 2); assertEquals(0, sub2.entrySet(false).size()); assertEquals(0, sub2.entrySet(true).size()); assertEquals(0, sub2_1.entrySet(false).size()); sub1.localDestroy("key4"); checkCollectionSize(1, 1); assertEquals(0, sub1.entrySet(false).size()); assertEquals(0, sub1.entrySet(true).size()); reg1.create("key3", "value3"); sub1.create("key4", "value4"); sub2.create("key5", "value5"); sub2_1.create("key6", "value6"); checkCollectionSize(2, 5); this.txMgr.begin(); this.region.create("key2", "value2"); checkCollectionSize(3, 6); reg1.localDestroy("key2"); checkCollectionSize(2, 5); this.region.create("key2", "value2"); checkCollectionSize(3, 6); reg1.destroy("key2"); checkCollectionSize(2, 5); reg1.put("key1", "value2"); checkCollectionSize(2, 5); this.region.create("key2", "value2"); checkCollectionSize(3, 6); reg1.localDestroy("key3"); checkCollectionSize(2, 5); reg1.create("key3", "value3"); checkCollectionSize(3, 6); // TX recursive checks sub2.destroy("key5"); checkCollectionSize(3, 5); assertEquals(1, sub1.entrySet(false).size()); assertEquals(1, sub1.entrySet(true).size()); assertEquals(0, sub2.entrySet(false).size()); assertEquals(1, sub2.entrySet(true).size()); assertEquals(1, sub2_1.entrySet(false).size()); assertEquals(1, sub2_1.entrySet(true).size()); sub2_1.destroy("key6"); checkCollectionSize(3, 4); assertEquals(1, sub1.entrySet(false).size()); assertEquals(1, sub1.entrySet(true).size()); assertEquals(0, sub2.entrySet(false).size()); assertEquals(0, sub2.entrySet(true).size()); assertEquals(0, sub2_1.entrySet(false).size()); assertEquals(0, sub2_1.entrySet(true).size()); sub1.localDestroy("key4"); checkCollectionSize(3, 3); assertEquals(0, sub1.entrySet(false).size()); assertEquals(0, sub1.entrySet(true).size()); assertEquals(0, sub2.entrySet(false).size()); assertEquals(0, sub2.entrySet(true).size()); assertEquals(0, sub2_1.entrySet(false).size()); assertEquals(0, sub2_1.entrySet(true).size()); sub2.put("key5", "value5"); checkCollectionSize(3, 4); assertEquals(0, sub1.entrySet(false).size()); assertEquals(0, sub1.entrySet(true).size()); assertEquals(1, sub2.entrySet(false).size()); assertEquals(1, sub2.entrySet(true).size()); assertEquals(0, sub2_1.entrySet(false).size()); assertEquals(0, sub2_1.entrySet(true).size()); sub2_1.put("key6", "value6"); checkCollectionSize(3, 5); assertEquals(0, sub1.entrySet(false).size()); assertEquals(0, sub1.entrySet(true).size()); assertEquals(1, sub2.entrySet(false).size()); assertEquals(2, sub2.entrySet(true).size()); assertEquals(1, sub2_1.entrySet(false).size()); assertEquals(1, sub2_1.entrySet(true).size()); sub1.put("key4", "value4"); checkCollectionSize(3, 6); assertEquals(1, sub1.entrySet(false).size()); assertEquals(1, sub1.entrySet(true).size()); assertEquals(1, sub2.entrySet(false).size()); assertEquals(2, sub2.entrySet(true).size()); assertEquals(1, sub2_1.entrySet(false).size()); assertEquals(1, sub2_1.entrySet(true).size()); sub2_1.put("key7", "value7"); checkCollectionSize(3, 7); assertEquals(1, sub1.entrySet(false).size()); assertEquals(1, sub1.entrySet(true).size()); assertEquals(1, sub2.entrySet(false).size()); assertEquals(3, sub2.entrySet(true).size()); assertEquals(2, sub2_1.entrySet(false).size()); assertEquals(2, sub2_1.entrySet(true).size()); this.txMgr.rollback(); checkCollectionSize(2, 5); // disabling these in a TX because they throw and don't work now! // this.txMgr.begin(); sub2.destroyRegion(); checkCollectionSize(2, 3); sub1.destroyRegion(); checkCollectionSize(2); // this.txMgr.rollback(); reg1.localDestroy("key1"); reg1.localDestroy("key3"); checkCollectionSize(0); } @Test public void testLoader() throws CacheException { LocalRegion reg1 = (LocalRegion) this.region; AttributesMutator mutator = reg1.getAttributesMutator(); mutator.setCacheLoader(new CacheLoader() { int count = 0; public Object load(LoaderHelper helper) throws CacheLoaderException { count++; return "LV " + count; } public void close() {} }); if (isPR()) ((PartitionedRegion) reg1).setHaveCacheLoader(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 1", reg1.get("key1")); assertTrue(reg1.containsKey("key1")); assertEquals("LV 1", reg1.getEntry("key1").getValue()); reg1.localDestroy("key1"); // TX load: only TX this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 2", reg1.get("key1")); assertTrue(reg1.containsKey("key1")); assertEquals("LV 2", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); assertTrue(!reg1.containsKey("key1")); // assertIndexDetailsEquals("LV 2", reg1.getEntry("key1").getValue()); // reg1.localDestroy("key1"); // TX load: commit check this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 3", reg1.get("key1")); assertTrue(reg1.containsKey("key1")); assertEquals("LV 3", reg1.getEntry("key1").getValue()); this.txMgr.commit(); assertTrue(reg1.containsKey("key1")); assertEquals("LV 3", reg1.getEntry("key1").getValue()); reg1.localDestroy("key1"); // TX load YES conflict: no-initial state, tx create, committed load { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; this.txMgr.begin(); reg1.create("key1", "txValue"); assertEquals("txValue", reg1.getEntry("key1").getValue()); tx = txMgrImpl.internalSuspend(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 4", reg1.get("key1")); assertTrue(reg1.containsKey("key1")); txMgrImpl.resume(tx); assertEquals("txValue", reg1.getEntry("key1").getValue()); assertEquals("txValue", reg1.get("key1")); try { this.txMgr.commit(); fail("Should have thrown a commit conflict"); } catch (CommitConflictException cce) { // this is what we want } assertEquals("LV 4", reg1.getEntry("key1").getValue()); assertEquals("LV 4", reg1.get("key1")); reg1.localDestroy("key1"); } // TX load no conflict: load initial state, tx update assertEquals("LV 5", reg1.get("key1")); this.txMgr.begin(); reg1.put("key1", "txValue"); assertEquals("txValue", reg1.get("key1")); assertEquals("txValue", reg1.getEntry("key1").getValue()); this.txMgr.commit(); // no conflict! Make sure committed value overrode initial state assertEquals("txValue", reg1.getEntry("key1").getValue()); assertEquals("txValue", reg1.get("key1")); reg1.localDestroy("key1"); // TX load no conflict: load initial state, tx load assertEquals("LV 6", reg1.get("key1")); this.txMgr.begin(); reg1.localInvalidate("key1"); assertEquals("LV 7", reg1.get("key1")); assertEquals("LV 7", reg1.getEntry("key1").getValue()); this.txMgr.commit(); // no conflict! Make sure committed value overrode initial state assertEquals("LV 7", reg1.getEntry("key1").getValue()); assertEquals("LV 7", reg1.get("key1")); reg1.localDestroy("key1"); // TX load no conflict: no initial state, tx load, committed create { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; this.txMgr.begin(); assertEquals("LV 8", reg1.get("key1")); assertEquals("LV 8", reg1.getEntry("key1").getValue()); tx = txMgrImpl.internalSuspend(); assertTrue(!reg1.containsKey("key1")); reg1.create("key1", "txValue"); assertTrue(reg1.containsKey("key1")); assertEquals("txValue", reg1.get("key1")); txMgrImpl.resume(tx); assertEquals("LV 8", reg1.getEntry("key1").getValue()); try { this.txMgr.commit(); // should conflict fail("Should have thrown cce"); } catch (CommitConflictException cce) { // this is what we want } assertEquals("txValue", reg1.getEntry("key1").getValue()); assertEquals("txValue", reg1.get("key1")); reg1.localDestroy("key1"); } // TX load conflict: no-inital state, tx load->update, committed update { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; this.txMgr.begin(); reg1.create("key1", "txValue"); tx = txMgrImpl.internalSuspend(); assertTrue(!reg1.containsKey("key1")); // new transaction, load(create) + put this.txMgr.begin(); assertEquals("LV 9", reg1.get("key1")); assertEquals("LV 9", reg1.getEntry("key1").getValue()); reg1.put("key1", "txValue2"); assertEquals("txValue2", reg1.get("key1")); assertEquals("txValue2", reg1.getEntry("key1").getValue()); this.txMgr.commit(); assertTrue(reg1.containsKey("key1")); assertEquals("txValue2", reg1.get("key1")); assertEquals("txValue2", reg1.getEntry("key1").getValue()); txMgrImpl.resume(tx); assertEquals("txValue", reg1.getEntry("key1").getValue()); assertEquals("txValue", reg1.get("key1")); try { this.txMgr.commit(); fail("expected CommitConflictException!"); } catch (CommitConflictException expected) { } assertTrue(reg1.containsKey("key1")); assertEquals("txValue2", reg1.get("key1")); assertEquals("txValue2", reg1.getEntry("key1").getValue()); reg1.localDestroy("key1"); } // TX load repeat: no-initial state, tx load->get this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 10", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 10", reg1.getEntry("key1").getValue()); assertEquals("LV 10", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 10", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: no-initial state, tx load->localDestory->load this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 11", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 11", reg1.getEntry("key1").getValue()); reg1.localDestroy("key1"); assertEquals("LV 12", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 12", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: no-initial state: tx load->destroy->load this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 13", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 13", reg1.getEntry("key1").getValue()); reg1.destroy("key1"); assertEquals("LV 14", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 14", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: no-initial state, tx load->localInvalidate->load this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 15", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 15", reg1.getEntry("key1").getValue()); reg1.localInvalidate("key1"); assertEquals("LV 16", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 16", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: no-initial, tx load->invalidate->load this.txMgr.begin(); assertTrue(!reg1.containsKey("key1")); assertEquals("LV 17", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 17", reg1.getEntry("key1").getValue()); reg1.invalidate("key1"); assertEquals("LV 18", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 18", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: invalid entry initial state, tx load->get reg1.create("key1", null); this.txMgr.begin(); assertTrue(reg1.containsKey("key1")); assertNull(reg1.getEntry("key1").getValue()); assertEquals("LV 19", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 19", reg1.getEntry("key1").getValue()); assertEquals("LV 19", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 19", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: invalid entry initial state, tx load->localDestory->load this.txMgr.begin(); assertTrue(reg1.containsKey("key1")); assertNull(reg1.getEntry("key1").getValue()); assertEquals("LV 20", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 20", reg1.getEntry("key1").getValue()); reg1.localDestroy("key1"); assertEquals("LV 21", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 21", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: invalid entry initial state: tx load->destroy->load this.txMgr.begin(); assertTrue(reg1.containsKey("key1")); assertNull(reg1.getEntry("key1").getValue()); assertEquals("LV 22", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 22", reg1.getEntry("key1").getValue()); reg1.destroy("key1"); assertEquals("LV 23", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 23", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: invalid entry initial state, tx load->localInvalidate->load this.txMgr.begin(); assertTrue(reg1.containsKey("key1")); assertNull(reg1.getEntry("key1").getValue()); assertEquals("LV 24", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 24", reg1.getEntry("key1").getValue()); reg1.localInvalidate("key1"); assertEquals("LV 25", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 25", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // TX load repeat: invalid entry initial state, tx load->invalidate->load this.txMgr.begin(); assertTrue(reg1.containsKey("key1")); assertNull(reg1.getEntry("key1").getValue()); assertEquals("LV 26", reg1.get("key1")); // first invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 26", reg1.getEntry("key1").getValue()); reg1.invalidate("key1"); assertEquals("LV 27", reg1.get("key1")); // second invocation assertTrue(reg1.containsKey("key1")); assertEquals("LV 27", reg1.getEntry("key1").getValue()); this.txMgr.rollback(); // Make sure a load does not conflict with the region being destroyed this.txMgr.begin(); assertEquals("LV 28", reg1.get("key2")); this.txMgr.commit(); reg1.localDestroyRegion(); // non-tx region op // reg1 is now destroyed } @Test public void testStats() throws CacheException { final int SLEEP_MS = 250; // final int OP_TIME = 0; // ns // changed form 10 to 0 because on fater platforms // and low resolution clocks this test will fail. final CachePerfStats stats = this.cache.getCachePerfStats(); class statsValidator { long txSuccessLifeTime; long txFailedLifeTime; long txRollbackLifeTime; int txCommits; int txFailures; int txRollbacks; long txCommitTime; long txFailureTime; long txRollbackTime; int txCommitChanges; int txFailureChanges; int txRollbackChanges; CachePerfStats stats; statsValidator(CachePerfStats stats) { this.stats = stats; } void reset() { this.txSuccessLifeTime = this.stats.getTxSuccessLifeTime(); this.txFailedLifeTime = this.stats.getTxFailedLifeTime(); this.txRollbackLifeTime = this.stats.getTxRollbackLifeTime(); this.txCommits = this.stats.getTxCommits(); this.txFailures = this.stats.getTxFailures(); this.txRollbacks = this.stats.getTxRollbacks(); this.txCommitTime = this.stats.getTxCommitTime(); this.txFailureTime = this.stats.getTxFailureTime(); this.txRollbackTime = this.stats.getTxRollbackTime(); this.txCommitChanges = this.stats.getTxCommitChanges(); this.txFailureChanges = this.stats.getTxFailureChanges(); this.txRollbackChanges = this.stats.getTxRollbackChanges(); } void setTxSuccessLifeTime(long txSuccessLifeTime) { this.txSuccessLifeTime = txSuccessLifeTime; } void setTxFailedLifeTime(long txFailedLifeTime) { this.txFailedLifeTime = txFailedLifeTime; } void setTxRollbackLifeTime(long txRollbackLifeTime) { this.txRollbackLifeTime = txRollbackLifeTime; } void setTxCommits(int txCommits) { this.txCommits = txCommits; } void setTxFailures(int txFailures) { this.txFailures = txFailures; } void setTxRollbacks(int txRollbacks) { this.txRollbacks = txRollbacks; } void setTxCommitTime(long txCommitTime) { this.txCommitTime = txCommitTime; } void setTxFailureTime(long txFailureTime) { this.txFailureTime = txFailureTime; } void setTxRollbackTime(long txRollbackTime) { this.txRollbackTime = txRollbackTime; } void setTxCommitChanges(int txCommitChanges) { this.txCommitChanges = txCommitChanges; } void setTxFailureChanges(int txFailureChanges) { this.txFailureChanges = txFailureChanges; } void setTxRollbackChanges(int txRollbackChanges) { this.txRollbackChanges = txRollbackChanges; } void assertValid() { assertEquals(this.txRollbacks, this.stats.getTxRollbacks()); assertEquals(this.txRollbackChanges, this.stats.getTxRollbackChanges()); if (Boolean .getBoolean(DistributionConfig.GEMFIRE_PREFIX + "cache.enable-time-statistics")) { assertTrue(this.txRollbackTime <= this.stats.getTxRollbackTime()); // assertTrue(this.txRollbackLifeTime+((SLEEP_MS-10)*1000000) <= // this.stats.getTxRollbackLifeTime()); assertTrue( "RollbackLifeTime " + this.txRollbackLifeTime + " is not <= " + this.stats.getTxRollbackLifeTime(), this.txRollbackLifeTime <= this.stats.getTxRollbackLifeTime()); assertTrue(this.txCommitTime <= this.stats.getTxCommitTime()); assertTrue(this.txSuccessLifeTime <= this.stats.getTxSuccessLifeTime()); assertTrue(this.txFailureTime <= this.stats.getTxFailureTime()); assertTrue( "FailedLifeTime " + this.txFailedLifeTime + " is not <= " + this.stats.getTxFailedLifeTime(), this.txFailedLifeTime <= this.stats.getTxFailedLifeTime()); } assertEquals(this.txCommits, this.stats.getTxCommits()); assertEquals(this.txCommitChanges, this.stats.getTxCommitChanges()); assertEquals(this.txFailures, this.stats.getTxFailures()); assertEquals(this.txFailureChanges, this.stats.getTxFailureChanges()); } } statsValidator statsVal = new statsValidator(stats); // Zero and non-zero rollback stats test int i; long testRollbackLifeTime = 0, testTotalTx = 0; for (i = 0; i < 2; ++i) { statsVal.reset(); statsVal.setTxRollbacks(stats.getTxRollbacks() + 1); statsVal.setTxRollbackLifeTime(stats.getTxRollbackLifeTime() + ((SLEEP_MS - 20) * 1000000)); final long beforeBegin = NanoTimer.getTime(); this.txMgr.begin(); final long afterBegin = NanoTimer.getTime(); pause(SLEEP_MS); if (i > 0) { statsVal.setTxRollbackChanges(stats.getTxRollbackChanges() + 2); this.region.put("stats1", "stats rollback1"); this.region.put("stats2", "stats rollback2"); } statsVal.setTxRollbackTime(stats.getTxRollbackTime()); final long beforeRollback = NanoTimer.getTime(); this.txMgr.rollback(); final long afterRollback = NanoTimer.getTime(); final long statsRollbackLifeTime = stats.getTxRollbackLifeTime(); testRollbackLifeTime += beforeRollback - afterBegin; // bruce - time based stats are disabled by default String p = (String) cache.getDistributedSystem().getProperties() .get(DistributionConfig.GEMFIRE_PREFIX + "enable-time-statistics"); if (p != null && Boolean.getBoolean(p)) { assertTrue("Local RollbackLifeTime assertion: " + testRollbackLifeTime + " is not <= " + statsRollbackLifeTime, testRollbackLifeTime <= statsRollbackLifeTime); } testTotalTx += afterRollback - beforeBegin; final long totalTXMinusRollback = testTotalTx - stats.getTxRollbackTime(); if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "cache.enable-time-statistics")) { assertTrue("Total Tx Minus Rollback assertion: " + totalTXMinusRollback + " is not >= " + statsRollbackLifeTime, totalTXMinusRollback >= statsRollbackLifeTime); } statsVal.assertValid(); } // Zero and non-zero commit stats test for (i = 0; i < 2; ++i) { statsVal.reset(); statsVal.setTxCommits(stats.getTxCommits() + 1); statsVal.setTxSuccessLifeTime(stats.getTxSuccessLifeTime() + ((SLEEP_MS - 10) * 1000000)); this.txMgr.begin(); pause(SLEEP_MS); if (i > 0) { statsVal.setTxCommitChanges(stats.getTxCommitChanges() + 2); this.region.put("stats1", "commit1"); this.region.put("stats2", "commit2"); } try { statsVal.setTxCommitTime(stats.getTxCommitTime()); this.txMgr.commit(); } catch (CommitConflictException ex) { fail("unexpected " + ex); } statsVal.assertValid(); } // Non-zero failed commit stats TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; statsVal.reset(); statsVal.setTxFailures(stats.getTxFailures() + 1); statsVal.setTxFailureChanges(stats.getTxFailureChanges() + 2); statsVal.setTxFailedLifeTime(stats.getTxFailedLifeTime() + ((SLEEP_MS - 20) * 1000000)); this.region.put("stats3", "stats fail3"); this.txMgr.begin(); this.region.put("stats1", "stats fail1"); this.region.put("stats2", "stats fail2"); try { this.region.create("stats3", "try stats3"); fail("expected EntryExistsException"); } catch (EntryExistsException ok) { } // begin other tx simulation TXStateProxy tx = txMgrImpl.internalSuspend(); this.region.put("stats1", "stats success1"); this.region.put("stats2", "stats success2"); txMgrImpl.resume(tx); // end other tx simulation pause(SLEEP_MS); try { statsVal.setTxFailureTime(stats.getTxFailureTime()); this.txMgr.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { // expected failure } statsVal.assertValid(); } @Test public void testCacheStats() throws CacheException { CachePerfStats cacheStats = this.cache.getCachePerfStats(); // quick sanity check to make sure perf stats work non-tx int creates; int destroys; int puts; int invalidates; creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.region.create("key1", "value1"); assertEquals(creates + 1, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts + 1, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.region.put("key1", "value2"); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts + 1, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.region.invalidate("key1"); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts, cacheStats.getPuts()); assertEquals(invalidates + 1, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.region.destroy("key1"); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys + 1, cacheStats.getDestroys()); assertEquals(puts, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); // now make sure they do not change from tx ops and from rollbacks creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.txMgr.begin(); this.region.create("key1", "value1"); this.region.put("key1", "value2"); this.region.invalidate("key1"); this.region.put("key1", "value3"); this.region.localInvalidate("key1"); this.region.put("key1", "value4"); this.region.localDestroy("key1"); this.region.put("key1", "value5"); this.region.destroy("key1"); this.txMgr.rollback(); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); // now make sure they do change when a commit is done creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.txMgr.begin(); this.region.create("key1", "value1"); assertEquals(creates, cacheStats.getCreates()); assertEquals(puts, cacheStats.getPuts()); this.txMgr.commit(); assertEquals(creates + 1, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts + 1, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.txMgr.begin(); this.region.put("key1", "value1"); assertEquals(puts, cacheStats.getPuts()); this.txMgr.commit(); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts + 1, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.txMgr.begin(); this.region.localInvalidate("key1"); assertEquals(invalidates, cacheStats.getInvalidates()); this.txMgr.commit(); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys, cacheStats.getDestroys()); assertEquals(puts, cacheStats.getPuts()); assertEquals(invalidates + 1, cacheStats.getInvalidates()); creates = cacheStats.getCreates(); destroys = cacheStats.getDestroys(); puts = cacheStats.getPuts(); invalidates = cacheStats.getInvalidates(); this.txMgr.begin(); this.region.localDestroy("key1"); assertEquals(destroys, cacheStats.getDestroys()); this.txMgr.commit(); assertEquals(creates, cacheStats.getCreates()); assertEquals(destroys + 1, cacheStats.getDestroys()); assertEquals(puts, cacheStats.getPuts()); assertEquals(invalidates, cacheStats.getInvalidates()); } private void pause(int msWait) { try { Thread.sleep(msWait); } catch (InterruptedException ignore) { fail("interrupted"); } } @Test public void testSuspendResume() { TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; assertTrue(!this.txMgr.exists()); assertEquals(null, txMgrImpl.internalSuspend()); TXStateProxy txProxy = null; txMgrImpl.resume(txProxy); assertTrue(!this.txMgr.exists()); this.txMgr.begin(); TransactionId origId = this.txMgr.getTransactionId(); assertTrue(this.txMgr.exists()); { TXStateProxy tx = txMgrImpl.internalSuspend(); assertTrue(!this.txMgr.exists()); this.txMgr.begin(); try { txMgrImpl.resume(tx); fail("expected IllegalStateException"); } catch (IllegalStateException expected) { } this.txMgr.rollback(); assertTrue(!this.txMgr.exists()); txMgrImpl.resume(tx); } assertTrue(this.txMgr.exists()); assertEquals(origId, this.txMgr.getTransactionId()); this.txMgr.rollback(); } @Test public void testPublicSuspendResume() { CacheTransactionManager txMgr = this.txMgr; assertTrue(!this.txMgr.exists()); assertEquals(null, txMgr.suspend()); TransactionId txId = null; try { txMgr.resume(txId); fail("expected IllegalStateException"); } catch (IllegalStateException e) { } assertTrue(!this.txMgr.exists()); this.txMgr.begin(); TransactionId origId = this.txMgr.getTransactionId(); assertTrue(this.txMgr.exists()); { TransactionId tx = txMgr.suspend(); assertTrue(!this.txMgr.exists()); this.txMgr.begin(); try { txMgr.resume(tx); fail("expected IllegalStateException"); } catch (IllegalStateException expected) { } this.txMgr.rollback(); assertTrue(!this.txMgr.exists()); txMgr.resume(tx); } assertTrue(this.txMgr.exists()); assertEquals(origId, this.txMgr.getTransactionId()); this.txMgr.rollback(); } @Test public void testCheckNoTX() { { AttributesFactory af = new AttributesFactory(); af.setScope(Scope.GLOBAL); Region gr = null; try { gr = this.cache.createRegion("GLOBALTXTest", af.create()); } catch (CacheException ex) { fail("did not expect " + ex); } try { gr.put("foo", "bar1"); } catch (Exception ex) { fail("did not expect " + ex); } this.txMgr.begin(); try { gr.put("foo", "bar2"); fail("expected UnsupportedOperationException"); } catch (UnsupportedOperationException expected) { } catch (Exception ex) { fail("did not expect " + ex); } this.txMgr.rollback(); } { DiskStoreFactory dsf = this.cache.createDiskStoreFactory(); dsf.create("testCheckNoTX"); AttributesFactory af = new AttributesFactory(); af.setScope(Scope.LOCAL); af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); af.setDiskStoreName("testCheckNoTX"); Region dr = null; try { dr = this.cache.createRegion("DiskTXTest", af.create()); } catch (CacheException ex) { fail("did not expect " + ex); } try { try { dr.put("foo", "bar1"); } catch (Exception ex) { fail("did not expect " + ex); } this.txMgr.begin(); try { dr.put("foo", "bar2"); fail("expected UnsupportedOperationException"); } catch (UnsupportedOperationException expected) { } catch (Exception ex) { fail("did not expect " + ex); } this.txMgr.rollback(); } finally { dr.localDestroyRegion(); } } } @Test public void testRepeatableRead() throws CacheException { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; // try repeating a get and make sure it doesn't cause a conflict this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals("value1", this.region.get("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals("value1", this.region.get("key1")); txMgrImpl.commit(); // try repeating a get and modify the entry and make sure it causes a conflict this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals("value1", this.region.get("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals("value1", this.region.get("key1")); this.region.put("key1", "value3"); assertEquals("value3", this.region.get("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try repeating a getEntry and make sure it doesn't cause a conflict this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); this.region.getEntry("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals("value1", this.region.get("key1")); txMgrImpl.commit(); // try repeating a getEntry and modify the entry and make sure it causes a conflict this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); this.region.getEntry("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); this.region.put("key1", "value3"); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try RR when entry fetched using entrySet this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); this.region.get("key1"); // bootstrap the tx, entrySet does not this.region.entrySet(false).iterator().next(); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals("value1", this.region.get("key1")); txMgrImpl.commit(); // try RRW->CONFLICT when entry fetched using entrySet this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); this.region.get("key1"); // bootstrap the tx, entrySet does not this.region.entrySet(false).iterator().next(); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals("value1", this.region.get("key1")); this.region.put("key1", "value3"); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try containsKey this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals(true, this.region.containsKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsKey("key1")); txMgrImpl.commit(); this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals(true, this.region.containsKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsKey("key1")); this.region.put("key1", "value3"); assertEquals(true, this.region.containsKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try containsValueForKey this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals(true, this.region.containsValueForKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsValueForKey("key1")); txMgrImpl.commit(); this.region.put("key1", "value1"); // non-tx txMgrImpl.begin(); assertEquals(true, this.region.containsValueForKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsValueForKey("key1")); this.region.put("key1", "value3"); assertEquals(true, this.region.containsValueForKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // now try the same things but with no entry in committed state at // the time of the first read // try repeating a get and make sure it doesn't cause a conflict this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(null, this.region.get("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(null, this.region.get("key1")); txMgrImpl.commit(); // try repeating a get and modify the entry and make sure it causes a conflict this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(null, this.region.get("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(null, this.region.get("key1")); this.region.put("key1", "value3"); assertEquals("value3", this.region.get("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try repeating a getEntry and make sure it doesn't cause a conflict this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(null, this.region.getEntry("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(null, this.region.getEntry("key1")); txMgrImpl.commit(); // try repeating a getEntry and modify the entry and make sure it causes a conflict this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(null, this.region.getEntry("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(null, this.region.getEntry("key1")); this.region.put("key1", "value3"); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try containsKey this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(false, this.region.containsKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(false, this.region.containsKey("key1")); txMgrImpl.commit(); this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(false, this.region.containsKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(false, this.region.containsKey("key1")); this.region.put("key1", "value3"); assertEquals(true, this.region.containsKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try containsValueForKey this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(false, this.region.containsValueForKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(false, this.region.containsValueForKey("key1")); txMgrImpl.commit(); this.region.remove("key1"); // non-tx txMgrImpl.begin(); assertEquals(false, this.region.containsValueForKey("key1")); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // non-tx txMgrImpl.resume(tx); assertEquals(false, this.region.containsValueForKey("key1")); this.region.put("key1", "value3"); assertEquals(true, this.region.containsValueForKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } // try an invalidate of an already invalid entry this.region.remove("key1"); // non-tx this.region.create("key1", null); // non-tx txMgrImpl.begin(); this.region.get("key1"); this.region.localInvalidate("key1"); // should be a noop since it is already invalid tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); txMgrImpl.commit(); assertEquals(false, this.region.containsKey("key1")); // make sure a noop invalidate is repeatable read this.region.remove("key1"); // non-tx this.region.create("key1", null); // non-tx txMgrImpl.begin(); this.region.localInvalidate("key1"); // should be a noop since it is already invalid tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsKey("key1")); assertEquals(false, this.region.containsValueForKey("key1")); txMgrImpl.commit(); assertEquals(false, this.region.containsKey("key1")); // make sure a destroy that throws entryNotFound is repeatable read this.region.remove("key1"); // non-tx txMgrImpl.begin(); try { this.region.localDestroy("key1"); fail("expected EntryNotFoundException"); } catch (EntryNotFoundException expected) { } tx = txMgrImpl.internalSuspend(); this.region.create("key1", "value1"); // non-tx txMgrImpl.resume(tx); assertEquals(false, this.region.containsKey("key1")); txMgrImpl.commit(); assertEquals(true, this.region.containsKey("key1")); this.region.remove("key1"); // non-tx // make sure a create that throws entryExists is repeatable read this.region.create("key1", "non-tx-value1"); // non-tx txMgrImpl.begin(); try { this.region.create("key1", "value1"); fail("expected EntryExistsException"); } catch (EntryExistsException expected) { } tx = txMgrImpl.internalSuspend(); this.region.remove("key1"); // non-tx txMgrImpl.resume(tx); assertEquals(true, this.region.containsKey("key1")); txMgrImpl.commit(); assertEquals(false, this.region.containsKey("key1")); } @Test public void testConflicts() throws CacheException { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; // try a put with no conflict to show that commit works txMgrImpl.begin(); this.region.put("key1", "value1"); txMgrImpl.commit(); assertEquals("value1", this.region.get("key1")); this.region.localDestroy("key1"); // now try a put with a conflict and make sure it is detected txMgrImpl.begin(); this.region.put("key1", "value1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // slightly difference version where value already exists in cmt state this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.put("key1", "value1"); txMgrImpl.commit(); assertEquals("value1", this.region.get("key1")); this.region.localDestroy("key1"); // now the conflict this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.put("key1", "value1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // now test create txMgrImpl.begin(); this.region.create("key1", "value1"); txMgrImpl.commit(); assertEquals("value1", this.region.get("key1")); this.region.localDestroy("key1"); // now try a create with a conflict and make sure it is detected txMgrImpl.begin(); this.region.create("key1", "value1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // test localInvalidate this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.localInvalidate("key1"); txMgrImpl.commit(); assertTrue(this.region.containsKey("key1") && !this.region.containsValueForKey("key1")); this.region.localDestroy("key1"); // now the conflict this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.localInvalidate("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // test invalidate this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.invalidate("key1"); txMgrImpl.commit(); assertTrue(this.region.containsKey("key1") && !this.region.containsValueForKey("key1")); this.region.localDestroy("key1"); // now the conflict this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.invalidate("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // check C + DD is a NOOP that still gets conflict if non-tx entry created */ this.txMgr.begin(); this.region.create("newKey", "valueTX"); tx = txMgrImpl.internalSuspend(); this.region.create("newKey", "valueNONTX"); txMgrImpl.resume(tx); this.region.destroy("newKey"); assertTrue(!this.region.containsKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("valueNONTX", this.region.get("newKey")); this.region.localDestroy("newKey"); // check C + LD is a NOOP that still gets conflict if non-tx entry created */ this.txMgr.begin(); this.region.create("newKey", "valueTX"); tx = txMgrImpl.internalSuspend(); this.region.create("newKey", "valueNONTX"); txMgrImpl.resume(tx); this.region.localDestroy("newKey"); assertTrue(!this.region.containsKey("key1")); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("valueNONTX", this.region.get("newKey")); this.region.localDestroy("newKey"); // test localDestroy this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.localDestroy("key1"); txMgrImpl.commit(); assertTrue(!this.region.containsKey("key1")); // now the conflict this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.localDestroy("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); // test destroy this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.destroy("key1"); txMgrImpl.commit(); assertTrue(!this.region.containsKey("key1")); // now the conflict this.region.put("key1", "value0"); txMgrImpl.begin(); this.region.destroy("key1"); tx = txMgrImpl.internalSuspend(); this.region.put("key1", "value2"); // do a non-tx put to force conflict txMgrImpl.resume(tx); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } assertEquals("value2", this.region.get("key1")); this.region.localDestroy("key1"); checkUserAttributeConflict(txMgrImpl); // make sure non-tx local-invalidate followed by invalidate // does not cause conflict this.region.create("key1", "val1"); this.region.localInvalidate("key1"); txMgrImpl.begin(); this.region.put("key1", "txVal1"); tx = txMgrImpl.internalSuspend(); this.region.invalidate("key1"); txMgrImpl.resume(tx); txMgrImpl.commit(); assertEquals("txVal1", this.region.getEntry("key1").getValue()); this.region.destroy("key1"); // now try a put and a region destroy. txMgrImpl.begin(); this.region.create("key1", "value1"); TXStateProxy tis = txMgrImpl.internalSuspend(); this.region.localDestroyRegion(); // non-tx txMgrImpl.resume(tis); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (TransactionException ex) { } // this.region is now destroyed } /** * @param txMgrImpl */ protected void checkUserAttributeConflict(final CacheTransactionManager txMgrImpl) { { // now check entry user attribute conflict checking this.region.put("key1", "value0"); Region.Entry cmtre = this.region.getEntry("key1"); assertEquals(null, cmtre.getUserAttribute()); txMgrImpl.begin(); Region.Entry txre = this.region.getEntry("key1"); txre.setUserAttribute("uaValue1"); txMgrImpl.commit(); assertEquals("uaValue1", cmtre.getUserAttribute()); this.region.localDestroy("key1"); this.region.put("key1", "value0"); cmtre = this.region.getEntry("key1"); assertEquals("value0", cmtre.getValue()); assertEquals(null, cmtre.getUserAttribute()); this.txMgr.begin(); txre = this.region.getEntry("key1"); assertEquals("value0", txre.getValue()); this.region.put("key1", "valueTX"); assertEquals("valueTX", txre.getValue()); assertEquals("value0", cmtre.getValue()); assertEquals(null, txre.getUserAttribute()); txre.setUserAttribute("uaValue1"); assertEquals("uaValue1", txre.getUserAttribute()); assertEquals(null, cmtre.getUserAttribute()); cmtre.setUserAttribute("uaValue2"); assertEquals("uaValue2", cmtre.getUserAttribute()); assertEquals("uaValue1", txre.getUserAttribute()); try { txMgrImpl.commit(); fail("expected CommitConflictException"); } catch (CommitConflictException ex) { } try { txre.getValue(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.isDestroyed(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.getUserAttribute(); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } try { txre.setUserAttribute("foo"); fail("expected IllegalStateException"); } catch (IllegalStateException ok) { } assertEquals("uaValue2", cmtre.getUserAttribute()); assertEquals("value0", cmtre.getValue()); this.region.localDestroy("key1"); } } @Test public void testNoopInvalidates() throws CacheException { final CachePerfStats stats = this.cache.getCachePerfStats(); TransactionListener tl = new TransactionListenerAdapter() { @Override public void afterRollback(TransactionEvent event) { te = event; } }; this.txMgr.addListener(tl); // Make sure invalidates done on invalid entries are noops { // distributed invalidate // first make sure invalidate is counted as a change int txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(1, te.getEvents().size()); this.region.destroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.txMgr.commit(); assertEquals(1, te.getEvents().size()); this.region.destroy("key1"); // now make sure a committed entry that is invalid is not counted as a change txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.region.invalidate("key1"); this.txMgr.begin(); this.region.invalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); assertEquals(0, te.getEvents().size()); this.region.destroy("key1"); this.region.create("key1", "value1"); this.region.invalidate("key1"); this.txMgr.begin(); this.region.invalidate("key1"); this.txMgr.commit(); assertEquals(0, te.getEvents().size()); this.region.destroy("key1"); // now make sure that multiple invalidates of same entry are a single change txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.region.invalidate("key1"); this.region.invalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); assertEquals(1, te.getEvents().size()); this.region.destroy("key1"); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.invalidate("key1"); this.region.invalidate("key1"); this.region.invalidate("key1"); this.txMgr.commit(); assertEquals(1, te.getEvents().size()); this.region.destroy("key1"); } { // local invalidate // first make sure invalidate is counted as a change int txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.localInvalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); this.region.destroy("key1"); // now make sure a committed entry that is invalid is not counted as a change txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.region.localInvalidate("key1"); this.txMgr.begin(); this.region.localInvalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges, stats.getTxRollbackChanges()); this.region.destroy("key1"); // now make sure that multiple localInvalidates of same entry are a single change txRollbackChanges = stats.getTxRollbackChanges(); this.region.create("key1", "value1"); this.txMgr.begin(); this.region.localInvalidate("key1"); this.region.localInvalidate("key1"); this.region.localInvalidate("key1"); this.txMgr.rollback(); assertEquals(txRollbackChanges + 1, stats.getTxRollbackChanges()); this.region.destroy("key1"); } } final static void clearRegion(Region r) throws TimeoutException { Iterator kI = r.keySet().iterator(); try { while (kI.hasNext()) { r.destroy(kI.next()); } } catch (CacheException ce) { fail("clearRegion operation failed"); } } final static int LRUENTRY_NULL = 0; final static int LRUENTRY_STRING = 1; final static int LRUENTRY_INTEGER = 2; final static int LRUENTRY_LONG = 3; final static int LRUENTRY_DOUBLE = 4; final static void assertLRUEntries(Set entries, int size, String keyPrefix, int instanceId) { assertEquals(size, entries.size()); Iterator entItr = entries.iterator(); while (entItr.hasNext()) { Region.Entry re = (Region.Entry) entItr.next(); switch (instanceId) { case LRUENTRY_NULL: assertNull(re.getValue()); break; case LRUENTRY_STRING: assertTrue(re.getValue() instanceof String); break; case LRUENTRY_INTEGER: assertTrue(re.getValue() instanceof Integer); break; case LRUENTRY_LONG: assertTrue(re.getValue() instanceof Long); break; case LRUENTRY_DOUBLE: assertTrue(re.getValue() instanceof Double); break; default: fail("Unknown instance type in assertLRUEntries: " + instanceId); } String reKey = (String) re.getKey(); assertTrue("expected " + reKey + " to start with " + keyPrefix, reKey.startsWith(keyPrefix)); } } @Test public void testEviction() throws CacheException { final int lruSize = 8; AttributesFactory af = new AttributesFactory(); af.setEvictionAttributes( EvictionAttributes.createLRUEntryAttributes(lruSize, EvictionAction.LOCAL_DESTROY)); af.setScope(Scope.LOCAL); Region lruRegion = this.cache.createRegion(getUniqueName(), af.create()); // Non-TX LRU verification assertEquals(0, lruRegion.entrySet(false).size()); int numToPut = lruSize + 2; for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); clearRegion(lruRegion); // TX LRU verification assertEquals(0, lruRegion.entrySet(false).size()); numToPut = lruSize + 2; this.txMgr.begin(); for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Long(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); this.txMgr.commit(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_LONG); clearRegion(lruRegion); // TX/non-TX no conflict verification w/ initial state // full+2, all committed entries have TX refs { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; numToPut = lruSize + 2; assertEquals(0, lruRegion.entrySet(false).size()); for (int i = 0; i < numToPut; ++i) { lruRegion.create("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); this.txMgr.begin(); for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Long(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); tx = txMgrImpl.internalSuspend(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); for (int i = 0; i < numToPut; ++i) { lruRegion.put("non-tx key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); assertNull(lruRegion.get("non-tx key0")); txMgrImpl.resume(tx); this.txMgr.commit(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_LONG); } clearRegion(lruRegion); // TX/non-TX no conflict verification w/ invalid initial state // full+2, all committed entries have TX refs using a loader { AttributesMutator mutator = lruRegion.getAttributesMutator(); mutator.setCacheLoader(new CacheLoader() { // int count = 0; public Object load(LoaderHelper helper) throws CacheLoaderException { return "value" + helper.getArgument(); } public void close() {} }); final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; numToPut = lruSize + 2; assertEquals(0, lruRegion.entrySet(false).size()); for (int i = 0; i < numToPut; ++i) { lruRegion.create("key" + i, null); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_NULL); // assertIndexDetailsEquals(lruSize, lruRegion.entrySet(false).size()); this.txMgr.begin(); for (int i = 0; i < numToPut; ++i) { lruRegion.get("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_STRING); tx = txMgrImpl.internalSuspend(); assertEquals(lruSize, lruRegion.entrySet(false).size()); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_NULL); for (int i = 0; i < numToPut; ++i) { lruRegion.get("non-tx key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_NULL); assertNull(lruRegion.getEntry("non-tx key0")); txMgrImpl.resume(tx); this.txMgr.commit(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_STRING); Iterator it = lruRegion.keySet().iterator(); while (it.hasNext()) { lruRegion.localInvalidate(it.next(), null); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_NULL); mutator.setCacheLoader(null); } clearRegion(lruRegion); // TX/TX/non-TX no conflict verification w/ initial state full, TX // add lruLimit+4, existing committed have TX 2 refs, force non-TX // eviction, force TX eviction { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx1, tx2; numToPut = lruSize + 4; assertEquals(0, lruRegion.entrySet(false).size()); // Create entries for (int i = 0; i < numToPut; ++i) { lruRegion.create("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); this.txMgr.begin(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Add a TX reference to committed entries, add a few on top of that for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Long(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); tx1 = txMgrImpl.internalSuspend(); this.txMgr.begin(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Add another TX reference to committed entries, add a few on top of that for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Double(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_DOUBLE); tx2 = txMgrImpl.internalSuspend(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // LocalRegion lrReg = (LocalRegion) lruRegion; // LRUClockNode lruE = null; // assertNotNull(lruE = (LRUClockNode) lrReg.basicGetEntry("key"+(numToPut-1))); // assertIndexDetailsEquals(2, lruE.getRefCount()); // assertIndexDetailsEquals(lruSize, lruRegion.entrySet(false).size()); // Force the Non-Tx "put" to remove each attempt since region is full // and all the committed entries are currently part of a TX for (int i = 0; i < numToPut; ++i) { lruRegion.put("non-tx key" + i, new Integer(i)); } assertTrue(numToPut > lruSize); assertNull(lruRegion.get("non-tx key0")); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); txMgrImpl.resume(tx1); assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); // Check to make sure no conflict was caused by non-TX put evictions // This should remove all references for each committed entry this.txMgr.commit(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_LONG); txMgrImpl.resume(tx2); assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_DOUBLE); this.txMgr.rollback(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_LONG); // Test to make sure we can evict something that has been rolled back for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, "value" + i); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_STRING); } clearRegion(lruRegion); // TX/non-TX no conflict verification w/ initial state full, TX // add lruLimit+4, force non-TX eviction, then rolls back, make // sure that non-TX eviction works properly { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; numToPut = lruSize + 4; assertEquals(0, lruRegion.entrySet(false).size()); // Create entries for (int i = 0; i < numToPut; ++i) { lruRegion.create("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); this.txMgr.begin(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Add a TX reference to committed entries, add a few on top of that for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Long(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); tx = txMgrImpl.internalSuspend(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Force the Non-Tx "put" to remove each attempt since region is full // and all the committed entries are currently part of a TX for (int i = 0; i < numToPut; ++i) { lruRegion.put("non-tx key" + i, new Integer(i)); } assertNull(lruRegion.get("non-tx key0")); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); txMgrImpl.resume(tx); assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); // This should remove all references for each committed entry this.txMgr.rollback(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Test to make sure we can evict something that has been rolled back for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, "value" + i); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_STRING); } clearRegion(lruRegion); // TX/TX conflict with initial state full, TX // add lruLimit+4, after failed commit make // sure that non-TX eviction works properly { final TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy tx; numToPut = lruSize + 4; assertEquals(0, lruRegion.entrySet(false).size()); // Create entries for (int i = 0; i < numToPut; ++i) { lruRegion.create("key" + i, new Integer(i)); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); this.txMgr.begin(); assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Add a TX reference to committed entries, add a few on top of that for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, new Long(i)); } assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); tx = txMgrImpl.internalSuspend(); // Cause a conflict lruRegion.put("key" + (numToPut - 1), new Integer(numToPut - 1)); txMgrImpl.resume(tx); assertLRUEntries(lruRegion.entrySet(false), numToPut, "key", LRUENTRY_LONG); // This should remove all references for each committed entry try { this.txMgr.commit(); fail("Expected CommitConflictException during commit LRU Eviction test!"); } catch (CommitConflictException ok) { } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER); // Test to make sure we can evict something that has been rolled back for (int i = 0; i < numToPut; ++i) { lruRegion.put("key" + i, "value" + i); } assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_STRING); } lruRegion.localDestroyRegion(); } @Test public void testJTASynchronization() throws CacheException, javax.transaction.NotSupportedException, javax.transaction.RollbackException, javax.transaction.SystemException, javax.transaction.HeuristicMixedException, javax.transaction.HeuristicRollbackException { javax.transaction.TransactionManager jtaTxMgr = this.cache.getJTATransactionManager(); TransactionListener tl = new TransactionListener() { public void afterCommit(TransactionEvent event) { ++listenerAfterCommit; te = event; } public void afterFailedCommit(TransactionEvent event) { ++listenerAfterFailedCommit; te = event; } public void afterRollback(TransactionEvent event) { ++listenerAfterRollback; te = event; } public void close() { ++listenerClose; } }; this.txMgr.addListener(tl); Synchronization gfTXSync; // Test successful JTA commit jtaTxMgr.begin(); this.txMgr.begin(); { TXManagerImpl gfTxMgrImpl = (TXManagerImpl) this.txMgr; gfTXSync = gfTxMgrImpl.getTXState(); } jtaTxMgr.getTransaction().registerSynchronization(gfTXSync); assertEquals(0, this.listenerAfterCommit); this.cache.getLogger().info("SWAP:doingCreate"); this.region.create("syncKey1", "syncVal1"); jtaTxMgr.commit(); assertEquals(1, this.listenerAfterCommit); assertEquals("syncVal1", this.region.getEntry("syncKey1").getValue()); try { this.txMgr.commit(); fail("JTA Cache Manager should have called commit!"); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable expected) { } // Test JTA rollback jtaTxMgr.begin(); this.txMgr.begin(); { TXManagerImpl gfTxMgrImpl = (TXManagerImpl) this.txMgr; gfTXSync = gfTxMgrImpl.getTXState(); } jtaTxMgr.getTransaction().registerSynchronization(gfTXSync); assertEquals(0, this.listenerAfterRollback); this.region.put("syncKey2", "syncVal2"); jtaTxMgr.rollback(); assertEquals(1, this.listenerAfterRollback); assertTrue(!this.region.containsKey("syncKey2")); // Test failed JTA commit with suspend jtaTxMgr.begin(); this.txMgr.begin(); { TXManagerImpl gfTxMgrImpl = (TXManagerImpl) this.txMgr; gfTXSync = gfTxMgrImpl.getTXState(); jtaTxMgr.getTransaction().registerSynchronization(gfTXSync); assertEquals(0, this.listenerAfterFailedCommit); this.region.put("syncKey3", "syncVal3"); assertEquals("syncVal3", this.region.getEntry("syncKey3").getValue()); TXStateProxy gfTx = gfTxMgrImpl.internalSuspend(); javax.transaction.Transaction jtaTx = jtaTxMgr.suspend(); assertNull(jtaTxMgr.getTransaction()); this.region.put("syncKey3", "syncVal4"); assertEquals("syncVal4", this.region.getEntry("syncKey3").getValue()); gfTxMgrImpl.resume(gfTx); try { jtaTxMgr.resume(jtaTx); } catch (Exception failure) { fail("JTA resume failed"); } assertNotNull(jtaTxMgr.getTransaction()); } assertEquals("syncVal3", this.region.getEntry("syncKey3").getValue()); try { jtaTxMgr.commit(); fail("Expected JTA manager conflict exception!"); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable expected) { } assertEquals(1, this.listenerAfterFailedCommit); assertEquals("syncVal4", this.region.getEntry("syncKey3").getValue()); // Test failed JTA commit with a new thread jtaTxMgr.begin(); this.txMgr.begin(); { TXManagerImpl gfTxMgrImpl = (TXManagerImpl) this.txMgr; gfTXSync = gfTxMgrImpl.getTXState(); jtaTxMgr.getTransaction().registerSynchronization(gfTXSync); assertEquals(1, this.listenerAfterFailedCommit); this.region.put("syncKey4", "syncVal3"); assertEquals("syncVal3", this.region.getEntry("syncKey4").getValue()); // Create a new thread and have it update the same key, causing // a conflict final int signal[] = {0}; Thread t = new Thread("non-TX conflict generator") { public void run() { try { region.put("syncKey4", "syncVal4"); while (true) synchronized (signal) { signal[0] = 1; signal.notify(); signal.wait(); if (signal[0] == 0) { break; } } } catch (Exception error) { fail("Non-tx thread failure due to: " + error); } } }; t.start(); try { while (true) synchronized (signal) { if (signal[0] == 1) { signal[0] = 0; signal.notify(); break; } else { signal.wait(); } } } catch (InterruptedException dangit) { fail("Tx thread waiting for non-tx thread failed due to : " + dangit); } assertEquals("syncVal3", this.region.getEntry("syncKey4").getValue()); } try { jtaTxMgr.commit(); fail("Expected JTA manager conflict exception!"); } catch (javax.transaction.HeuristicRollbackException expected) { } catch (javax.transaction.RollbackException alsoExpected) { } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable yuk) { fail("Did not expect this throwable from JTA commit: " + yuk); } assertEquals(2, this.listenerAfterFailedCommit); assertEquals("syncVal4", this.region.getEntry("syncKey4").getValue()); this.txMgr.removeListener(tl); } @Test public void testJTAEnlistment() throws CacheException, javax.transaction.NotSupportedException, javax.transaction.RollbackException, javax.transaction.SystemException, javax.transaction.HeuristicMixedException, javax.transaction.HeuristicRollbackException { TransactionListener tl = new TransactionListener() { public void afterCommit(TransactionEvent event) { ++listenerAfterCommit; te = event; } public void afterFailedCommit(TransactionEvent event) { ++listenerAfterFailedCommit; te = event; } public void afterRollback(TransactionEvent event) { ++listenerAfterRollback; te = event; } public void close() { ++listenerClose; } }; this.txMgr.addListener(tl); javax.transaction.UserTransaction userTx = null; try { userTx = (javax.transaction.UserTransaction) this.cache.getJNDIContext() .lookup("java:/UserTransaction"); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable badDog) { fail("Expected to get a healthy UserTransaction!"); } // Test enlistement for put // Test enlisted rollback // Test prevention of rollback/commit for enlisted transaction assertEquals(0, this.listenerAfterRollback); userTx.begin(); this.region.put("enlistKey", "enlistVal"); assertEquals("enlistVal", this.region.getEntry("enlistKey").getValue()); assertNotNull(this.txMgr.getTransactionId()); try { this.txMgr.rollback(); fail("Should not allow a CacheTransactionManager.rollback call once the GF Tx is enlisted"); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable ok) { } try { this.txMgr.commit(); fail("Should not allow a CacheTransactionManager.commit() call once the GF Tx is enlisted"); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (Throwable alsoOk) { } userTx.rollback(); assertNull(this.txMgr.getTransactionId()); assertTrue(!this.region.containsKey("enlistKey")); assertEquals(1, this.listenerAfterRollback); // Test enlistement for create // Test commit assertEquals(0, this.listenerAfterCommit); userTx.begin(); this.region.create("enlistKey", "enlistVal"); assertEquals("enlistVal", this.region.getEntry("enlistKey").getValue()); assertNotNull(this.txMgr.getTransactionId()); userTx.commit(); assertNull(this.txMgr.getTransactionId()); assertTrue(this.region.containsKey("enlistKey")); assertEquals("enlistVal", this.region.getEntry("enlistKey").getValue()); assertEquals(1, this.listenerAfterCommit); // Test enlistement for get assertEquals(1, this.listenerAfterCommit); userTx.begin(); assertEquals("enlistVal", this.region.get("enlistKey")); assertNotNull(this.txMgr.getTransactionId()); userTx.commit(); assertNull(this.txMgr.getTransactionId()); assertEquals(2, this.listenerAfterCommit); // Test enlistement for invalidate assertEquals(2, this.listenerAfterCommit); userTx.begin(); this.region.invalidate("enlistKey"); assertTrue(this.region.containsKey("enlistKey")); assertTrue(!this.region.containsValueForKey("enlistKey")); assertNotNull(this.txMgr.getTransactionId()); userTx.commit(); assertNull(this.txMgr.getTransactionId()); assertTrue(this.region.containsKey("enlistKey")); assertTrue(!this.region.containsValueForKey("enlistKey")); assertEquals(3, this.listenerAfterCommit); // Test enlistement for destroy assertEquals(3, this.listenerAfterCommit); userTx.begin(); this.region.destroy("enlistKey"); assertTrue(!this.region.containsKey("enlistKey")); assertNotNull(this.txMgr.getTransactionId()); userTx.commit(); assertNull(this.txMgr.getTransactionId()); assertTrue(!this.region.containsKey("enlistKey")); assertEquals(4, this.listenerAfterCommit); // Test enlistment for load AttributesMutator mutator = this.region.getAttributesMutator(); mutator.setCacheLoader(new CacheLoader() { int count = 0; public Object load(LoaderHelper helper) throws CacheLoaderException { return new Integer(count++); } public void close() {} }); assertEquals(4, this.listenerAfterCommit); userTx.begin(); assertEquals(new Integer(0), this.region.get("enlistKey")); assertNotNull(this.txMgr.getTransactionId()); userTx.commit(); assertNull(this.txMgr.getTransactionId()); assertTrue(this.region.containsKey("enlistKey")); assertEquals(new Integer(0), this.region.getEntry("enlistKey").getValue()); assertEquals(5, this.listenerAfterCommit); mutator.setCacheLoader(null); // Test enlisted failed commit assertEquals(0, this.listenerAfterFailedCommit); userTx.begin(); this.region.put("enlistKey", "enlistVal"); assertEquals("enlistVal", this.region.get("enlistKey")); assertNotNull(this.txMgr.getTransactionId()); { TXManagerImpl gfTxMgrImpl = (TXManagerImpl) this.txMgr; TXStateProxy gfTx = gfTxMgrImpl.internalSuspend(); javax.transaction.TransactionManager jtaTxMgr = this.cache.getJTATransactionManager(); javax.transaction.Transaction jtaTx = jtaTxMgr.suspend(); this.region.put("enlistKey", "conflictVal"); assertEquals("conflictVal", this.region.get("enlistKey")); try { jtaTxMgr.resume(jtaTx); } catch (Exception failure) { fail("JTA resume failed"); } gfTxMgrImpl.resume(gfTx); } assertEquals("enlistVal", this.region.get("enlistKey")); try { userTx.commit(); fail("Expected JTA commit exception!"); } catch (javax.transaction.HeuristicRollbackException expected) { } catch (javax.transaction.RollbackException alsoExpected) { } catch (Exception yuk) { fail("Did not expect this exception from JTA commit: " + yuk); } assertNull(this.txMgr.getTransactionId()); assertEquals("conflictVal", this.region.getEntry("enlistKey").getValue()); assertEquals(1, this.listenerAfterFailedCommit); // Test rollbackOnly UserTransaction enlistment userTx.begin(); assertNull(this.txMgr.getTransactionId()); userTx.setRollbackOnly(); assertEquals(javax.transaction.Status.STATUS_MARKED_ROLLBACK, userTx.getStatus()); try { this.region.put("enlistKey", "enlistVal2"); fail("Expected to get a FailedSynchronizationException!"); } catch (FailedSynchronizationException okay) { } assertNull(this.txMgr.getTransactionId()); try { assertEquals("conflictVal", this.region.getEntry("enlistKey").getValue()); fail("Expected to get a FailedSynchronizationException!"); } catch (FailedSynchronizationException okay) { } assertTrue(!this.region.containsKey("enlistKey2")); try { this.region.put("enlistKey2", "enlistVal3"); fail("Expected to get a FailedSynchronizationException!"); } catch (FailedSynchronizationException okay) { } assertNull(this.txMgr.getTransactionId()); try { assertEquals("conflictVal", this.region.getEntry("enlistKey").getValue()); fail("Expected to get a FailedSynchronizationException!"); } catch (FailedSynchronizationException okay) { } assertTrue(!this.region.containsKey("enlistKey2")); userTx.rollback(); assertEquals("conflictVal", this.region.getEntry("enlistKey").getValue()); assertTrue(!this.region.containsKey("enlistKey2")); this.txMgr.removeListener(tl); } private static void waitForUpdates(final Index idx, final int expectedUpdates) { // DistributedTestCase.WaitCriterion wc = new DistributedTestCase.WaitCriterion() { // String excuse; // public boolean done() { // return idx.getStatistics().getNumUpdates() == expectedUpdates; // } // // public String description() { // return "expectedUpdates " + expectedUpdates + " but got this " // + idx.getStatistics().getNumUpdates(); // } // }; // DistributedTestCase.waitForCriterion(wc, 15 * 1000, 20, true); boolean done = false; try { for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < 15 * 1000; done = (idx.getStatistics().getNumUpdates() == expectedUpdates)) { Thread.sleep(20); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } assertTrue("expectedUpdates " + expectedUpdates + " but got this " + idx.getStatistics().getNumUpdates(), done); } private static void waitForKeys(final Index idx, final int expectedKeys) { // DistributedTestCase.WaitCriterion wc = new DistributedTestCase.WaitCriterion() { // String excuse; // public boolean done() { // return idx.getStatistics().getNumberOfKeys() == expectedKeys; // } // // public String description() { // return "expectedKeys " + expectedKeys + " but got this " // + idx.getStatistics().getNumberOfKeys(); // } // }; // DistributedTestCase.waitForCriterion(wc, 15 * 1000, 20, true); boolean done = false; try { for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < 15 * 1000; done = (idx.getStatistics().getNumberOfKeys() == expectedKeys)) { Thread.sleep(20); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } assertTrue( "expectedKeys " + expectedKeys + " but got this " + idx.getStatistics().getNumberOfKeys(), done); } @Test public void testTXAndQueries() throws CacheException, QueryException { IndexManager.TEST_RANGEINDEX_ONLY = true; try { final QueryService qs = this.cache.getQueryService(); final String fromClause = this.region.getFullPath() + " value "; final String qstr = "SELECT DISTINCT * FROM " + fromClause; // Create a region with async index updates AttributesFactory af = new AttributesFactory(this.region.getAttributes()); af.setIndexMaintenanceSynchronous(false); final Region aIregion = this.cache.createRegion(getUniqueName(), af.create()); final String aIfromClause = aIregion.getFullPath() + " value "; final String aIqstr = "SELECT DISTINCT * FROM " + aIfromClause; // Confirm base functionality for query results this.region.put("qkey0", "qval0"); this.region.put("qkey1", "qval01"); Query q = qs.newQuery(qstr); SelectResults res = (SelectResults) q.execute(); assertEquals(2, res.size()); String val; for (Iterator resI = res.iterator(); resI.hasNext();) { val = (String) resI.next(); assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval")); } q = qs.newQuery(qstr + " where value.length > 6"); res = (SelectResults) q.execute(); assertEquals(0, res.size()); aIregion.put("qkey0", "qval0"); aIregion.put("qkey1", "qval01"); q = qs.newQuery(aIqstr); res = (SelectResults) q.execute(); assertEquals(2, res.size()); for (Iterator resI = res.iterator(); resI.hasNext();) { val = (String) resI.next(); assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval")); } q = qs.newQuery(qstr + " where value.length > 6"); res = (SelectResults) q.execute(); assertEquals(0, res.size()); // Test query results in a transaction this.txMgr.begin(); Query q1 = qs.newQuery(qstr); this.region.put("noQkey2", "noQval2"); res = (SelectResults) q1.execute(); assertEquals(2, res.size()); for (Iterator resI = res.iterator(); resI.hasNext();) { val = (String) resI.next(); assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval")); } Query aIq1 = qs.newQuery(aIqstr); aIregion.put("noQkey2", "noQval2"); res = (SelectResults) aIq1.execute(); assertEquals(2, res.size()); for (Iterator resI = res.iterator(); resI.hasNext();) { val = (String) resI.next(); assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval")); } Query q2 = qs.newQuery(qstr + " where value.length > 6"); res = (SelectResults) q2.execute(); assertEquals(0, res.size()); Query aIq2 = qs.newQuery(aIqstr + " where value.length > 6"); res = (SelectResults) aIq2.execute(); assertEquals(0, res.size()); this.txMgr.commit(); res = (SelectResults) q1.execute(); assertEquals(3, res.size()); res = (SelectResults) q2.execute(); assertEquals(1, res.size()); res = (SelectResults) aIq1.execute(); assertEquals(3, res.size()); res = (SelectResults) aIq2.execute(); assertEquals(1, res.size()); this.region.destroy("noQkey2"); aIregion.destroy("noQkey2"); // Confirm base functionality for index creation Index index0 = qs.createIndex("TXIndex0", IndexType.FUNCTIONAL, "value.length", fromClause); assertEquals(2, index0.getStatistics().getNumberOfKeys()); assertEquals(2, index0.getStatistics().getNumberOfValues()); assertEquals(2, index0.getStatistics().getNumUpdates()); // Shouldn't this be zero? Index aIindex0 = qs.createIndex("aITXIndex0", IndexType.FUNCTIONAL, "value.length", aIfromClause); assertEquals(2, aIindex0.getStatistics().getNumberOfKeys()); assertEquals(2, aIindex0.getStatistics().getNumberOfValues()); assertEquals(2, aIindex0.getStatistics().getNumUpdates()); // Shouldn't this be zero? q = qs.newQuery(qstr); res = (SelectResults) q.execute(); assertEquals(2, res.size()); assertEquals(0, index0.getStatistics().getTotalUses()); aIq1 = qs.newQuery(aIqstr); res = (SelectResults) aIq1.execute(); assertEquals(2, res.size()); assertEquals(0, aIindex0.getStatistics().getTotalUses()); final String val2 = "qval000002"; this.region.put("qkey2", val2); assertEquals(3, index0.getStatistics().getNumUpdates()); // Shouldn't this be 1? assertEquals(3, index0.getStatistics().getNumberOfKeys()); assertEquals(3, index0.getStatistics().getNumberOfValues()); aIregion.put("qkey2", val2); final IndexManager.IndexUpdaterThread upThread = ((AbstractRegion) aIregion).getIndexManager().getUpdaterThread(); while (!upThread.isDone()) { pause(20); } // @todo asif: for some reason the value returned by getNumberOfKeys is unstable. // Even when the code waits for it to be the expected value it intermittently // will fail because it never gets to be the expected value. // This stat (in RangeIndex at least) is only updated when we add a new key // to the valueToEntriesMap. I do not see a place that we ever remove from // this map (even when we do a removeMapping). waitForUpdates(aIindex0, 3); waitForKeys(aIindex0, 3); assertEquals(3, aIindex0.getStatistics().getNumUpdates()); // Shouldn't this be 1? assertEquals(3, aIindex0.getStatistics().getNumberOfKeys()); assertEquals(3, aIindex0.getStatistics().getNumberOfValues()); q = qs.newQuery("ELEMENT(" + qstr + " where value.length > 6)"); assertEquals(val2, (String) q.execute()); assertEquals(1, index0.getStatistics().getTotalUses()); aIq1 = qs.newQuery("ELEMENT(" + aIqstr + " where value.length > 6)"); assertEquals(val2, (String) aIq1.execute()); this.region.destroy("qkey2"); waitForKeys(index0, 2); assertEquals(2, index0.getStatistics().getNumberOfKeys()); // Shouldn't this be 1, again? assertEquals(2, index0.getStatistics().getNumberOfValues()); assertEquals(4, index0.getStatistics().getNumUpdates()); aIregion.destroy("qkey2"); while (!upThread.isDone()) { pause(20); } waitForUpdates(aIindex0, 4); // waitForKeys(aIindex0, 3); // assertIndexDetailsEquals(3, aIindex0.getStatistics().getNumberOfKeys()); // Shouldn't this // be 1, again? assertEquals(2, aIindex0.getStatistics().getNumberOfValues()); assertEquals(4, aIindex0.getStatistics().getNumUpdates()); // Test index creation this.txMgr.begin(); this.region.destroy("qkey1"); this.region.put("noQkey3", "noQval3"); Index index1 = qs.createIndex("TXIndex1", IndexType.FUNCTIONAL, "value", fromClause); assertEquals(2, index1.getStatistics().getNumberOfKeys()); assertEquals(2, index1.getStatistics().getNumberOfValues()); assertEquals(2, index1.getStatistics().getNumUpdates()); assertEquals(2, index0.getStatistics().getNumberOfKeys()); assertEquals(2, index0.getStatistics().getNumberOfValues()); assertEquals(4, index0.getStatistics().getNumUpdates()); aIregion.destroy("qkey1"); aIregion.put("noQkey3", "noQval3"); Index aIindex1 = qs.createIndex("aITXIndex1", IndexType.FUNCTIONAL, "value", aIfromClause); while (!upThread.isDone()) { pause(20); } waitForUpdates(aIindex0, 4); waitForUpdates(aIindex1, 2); // waitForKeys(aIindex0, 3); // waitForKeys(aIindex1, 2); assertEquals(2, aIindex1.getStatistics().getNumberOfKeys()); assertEquals(2, aIindex1.getStatistics().getNumberOfValues()); assertEquals(2, aIindex1.getStatistics().getNumUpdates()); // assertIndexDetailsEquals(3, aIindex0.getStatistics().getNumberOfKeys()); assertEquals(2, aIindex0.getStatistics().getNumberOfValues()); assertEquals(4, aIindex0.getStatistics().getNumUpdates()); q = qs.newQuery(qstr); res = (SelectResults) q.execute(); assertEquals(2, res.size()); assertEquals(0, index1.getStatistics().getTotalUses()); assertEquals(1, index0.getStatistics().getTotalUses()); aIq1 = qs.newQuery(aIqstr); res = (SelectResults) aIq1.execute(); assertEquals(2, res.size()); assertEquals(0, aIindex1.getStatistics().getTotalUses()); assertEquals(1, aIindex0.getStatistics().getTotalUses()); q = qs.newQuery(qstr + " where value < 'q'"); res = (SelectResults) q.execute(); assertEquals(1, index1.getStatistics().getTotalUses()); assertEquals(0, res.size()); aIq1 = qs.newQuery(aIqstr + " where value < 'q'"); res = (SelectResults) aIq1.execute(); assertEquals(1, aIindex1.getStatistics().getTotalUses()); assertEquals(0, res.size()); this.region.put("noQkey4", "noQval4"); assertEquals(2, index1.getStatistics().getNumberOfKeys()); assertEquals(2, index1.getStatistics().getNumberOfValues()); assertEquals(2, index1.getStatistics().getNumUpdates()); assertEquals(2, index0.getStatistics().getNumberOfKeys()); assertEquals(2, index0.getStatistics().getNumberOfValues()); assertEquals(4, index0.getStatistics().getNumUpdates()); aIregion.put("noQkey4", "noQval4"); while (!upThread.isDone()) { pause(20); } waitForUpdates(aIindex0, 4); waitForUpdates(aIindex1, 2); waitForKeys(aIindex0, 2); // waitForKeys(aIindex1, 2); // assertIndexDetailsEquals(2, aIindex1.getStatistics().getNumberOfKeys()); assertEquals(2, aIindex1.getStatistics().getNumberOfValues()); assertEquals(2, aIindex1.getStatistics().getNumUpdates()); assertEquals(2, aIindex0.getStatistics().getNumberOfKeys()); assertEquals(2, aIindex0.getStatistics().getNumberOfValues()); assertEquals(4, aIindex0.getStatistics().getNumUpdates()); q = qs.newQuery(qstr + " where value < 'q'"); res = (SelectResults) q.execute(); assertEquals(2, index1.getStatistics().getTotalUses()); assertEquals(0, res.size()); aIq1 = qs.newQuery(aIqstr + " where value <'q'"); res = (SelectResults) aIq1.execute(); assertEquals(2, aIindex1.getStatistics().getTotalUses()); assertEquals(0, res.size()); q = qs.newQuery(qstr + " where value.length > 6"); res = (SelectResults) q.execute(); assertEquals(2, index0.getStatistics().getTotalUses()); assertEquals(0, res.size()); aIq1 = qs.newQuery(aIqstr + " where value.length > 6"); res = (SelectResults) aIq1.execute(); assertEquals(2, aIindex0.getStatistics().getTotalUses()); assertEquals(0, res.size()); this.txMgr.commit(); assertEquals(3, index1.getStatistics().getNumberOfKeys()); assertEquals(3, index1.getStatistics().getNumberOfValues()); // Shouldn't this be 4? assertEquals(5, index1.getStatistics().getNumUpdates()); assertEquals(2, index0.getStatistics().getNumberOfKeys()); assertEquals(3, index0.getStatistics().getNumberOfValues()); // Shouldn't this be 4? assertEquals(7, index0.getStatistics().getNumUpdates()); while (!upThread.isDone()) { pause(20); } waitForUpdates(aIindex0, 7); waitForUpdates(aIindex1, 5); // waitForKeys(aIindex0, 4); // sometimes 3 sometimes 4 // waitForKeys(aIindex1, 3); assertEquals(3, aIindex1.getStatistics().getNumberOfKeys()); assertEquals(3, aIindex1.getStatistics().getNumberOfValues()); // Shouldn't this be 4? assertEquals(5, aIindex1.getStatistics().getNumUpdates()); // assertIndexDetailsEquals(4, aIindex0.getStatistics().getNumberOfKeys()); assertEquals(3, aIindex0.getStatistics().getNumberOfValues()); // Shouldn't this be 4? assertEquals(7, aIindex0.getStatistics().getNumUpdates()); q = qs.newQuery(qstr + " where value <'q'"); res = (SelectResults) q.execute(); assertEquals(3, index1.getStatistics().getTotalUses()); assertEquals(2, res.size()); aIq1 = qs.newQuery(aIqstr + " where value < 'q'"); res = (SelectResults) aIq1.execute(); assertEquals(3, aIindex1.getStatistics().getTotalUses()); assertEquals(2, res.size()); q = qs.newQuery(qstr + " where value.length > 6"); res = (SelectResults) q.execute(); assertEquals(3, index0.getStatistics().getTotalUses()); assertEquals(2, res.size()); aIq1 = qs.newQuery(aIqstr + " where value.length > 6"); res = (SelectResults) aIq1.execute(); assertEquals(3, aIindex0.getStatistics().getTotalUses()); assertEquals(2, res.size()); } finally { IndexManager.TEST_RANGEINDEX_ONLY = false; } } /** * make sure that we do not expose BucketRegion on transactionListener events * * @throws Exception */ @Test public void testInternalRegionNotExposed() throws Exception { TransactionListenerForRegionTest tl = new TransactionListenerForRegionTest(); CacheTransactionManager ctm = this.cache.getCacheTransactionManager(); ctm.addListener(tl); CacheListenerForRegionTest cl = new CacheListenerForRegionTest(); AttributesFactory af = new AttributesFactory(); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); af.addCacheListener(cl); Region pr = this.cache.createRegion("testTxEventForRegion", af.create()); pr.put(2, "tw"); pr.put(3, "three"); pr.put(4, "four"); ctm.begin(); pr.put(1, "one"); pr.put(2, "two"); pr.invalidate(3); pr.destroy(4); ctm.commit(); assertFalse(tl.exceptionOccurred); assertFalse(cl.exceptionOccurred); } /** * make sure that we throw an UnsupportedOperationInTransactionException * * @throws Exception */ @Test public void testPutAllSupported() throws Exception { TXManagerImpl ctm = this.cache.getTxManager(); AttributesFactory af = new AttributesFactory(); Region r = this.cache.createRegion("dRegion", af.create()); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); Region pr = this.cache.createRegion("prRegion", af.create()); Map map = new HashMap(); map.put("stuff", "junk"); map.put("stuff2", "junk2"); ctm.begin(); pr.putAll(map); r.putAll(map); TXStateProxy tx = ctm.internalSuspend(); assertTrue(!pr.containsKey("stuff")); assertTrue(!r.containsKey("stuff")); ctm.resume(tx); ctm.commit(); assertTrue(pr.containsKey("stuff")); assertTrue(r.containsKey("stuff")); } /** * make sure that we throw an UnsupportedOperationInTransactionException * * @throws Exception */ @Test public void testGetAllSupported() throws Exception { CacheTransactionManager ctm = this.cache.getCacheTransactionManager(); AttributesFactory af = new AttributesFactory(); Region r = this.cache.createRegion("dRegion", af.create()); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); Region pr = this.cache.createRegion("prRegion", af.create()); List list = new ArrayList(); list.add("stuff"); list.add("stuff2"); ctm.begin(); pr.getAll(list); r.getAll(list); ctm.commit(); // now we aren't in tx so these shouldn't throw pr.getAll(list); r.getAll(list); } /** * make sure that we throw an UnsupportedOperationInTransactionException * * @throws Exception */ @Test public void testDestroyRegionNotSupported() throws Exception { CacheTransactionManager ctm = this.cache.getCacheTransactionManager(); AttributesFactory af = new AttributesFactory(); Region r = this.cache.createRegion("dRegion", af.create()); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); Region pr = this.cache.createRegion("prRegion", af.create()); List list = new ArrayList(); list.add("stuff"); list.add("stuff2"); ctm.begin(); try { pr.destroyRegion(); fail("Should have thrown UnsupportedOperationInTransactionException during destroyRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { pr.localDestroyRegion(); fail( "Should have thrown UnsupportedOperationInTransactionException during localDestroyRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { r.destroyRegion(); fail("Should have thrown UnsupportedOperationInTransactionException during destroyRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { r.localDestroyRegion(); fail( "Should have thrown UnsupportedOperationInTransactionException during localDestroyRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } assertTrue(!pr.isDestroyed()); assertTrue(!r.isDestroyed()); ctm.commit(); // now we aren't in tx so these shouldn't throw pr.destroyRegion(); r.destroyRegion(); } /** * make sure that we throw an UnsupportedOperationInTransactionException * * @throws Exception */ @Test public void testInvalidateRegionNotSupported() throws Exception { CacheTransactionManager ctm = this.cache.getCacheTransactionManager(); AttributesFactory af = new AttributesFactory(); Region r = this.cache.createRegion("dRegion", af.create()); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); Region pr = this.cache.createRegion("prRegion", af.create()); ctm.begin(); try { pr.invalidateRegion(); fail("Should have thrown UnsupportedOperationInTransactionException during invalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { pr.localInvalidateRegion(); fail( "Should have thrown UnsupportedOperationInTransactionException during localInvalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { r.invalidateRegion(); fail("Should have thrown UnsupportedOperationInTransactionException during invalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { r.localInvalidateRegion(); fail( "Should have thrown UnsupportedOperationInTransactionException during localInvalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } ctm.commit(); // now we aren't in tx so these shouldn't throw pr.invalidateRegion(); r.invalidateRegion(); } /** * make sure that we throw an UnsupportedOperationInTransactionException * * @throws Exception */ @Test public void testClearRegionNotSupported() throws Exception { CacheTransactionManager ctm = this.cache.getCacheTransactionManager(); AttributesFactory af = new AttributesFactory(); Region r = this.cache.createRegion("dRegion", af.create()); PartitionAttributes pa = new PartitionAttributesFactory().setRedundantCopies(0).setTotalNumBuckets(1).create(); af.setPartitionAttributes(pa); Region pr = this.cache.createRegion("prRegion", af.create()); ctm.begin(); try { pr.clear(); fail("Should have thrown UnsupportedOperation during invalidateRegion"); } catch (UnsupportedOperationException ee) { // expected } try { pr.localClear(); fail("Should have thrown UnsupportedOperation during localInvalidateRegion"); } catch (UnsupportedOperationException ee) { // expected } try { r.clear(); fail("Should have thrown UnsupportedOperationInTransactionException during invalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } try { r.localClear(); fail( "Should have thrown UnsupportedOperationInTransactionException during localInvalidateRegion"); } catch (UnsupportedOperationInTransactionException ee) { // expected } ctm.commit(); // now we aren't in tx so these shouldn't throw pr.invalidateRegion(); r.invalidateRegion(); } @Test public void testBug51781() { AttributesFactory<Integer, String> af = new AttributesFactory<Integer, String>(); af.setDataPolicy(DataPolicy.NORMAL); Region<Integer, String> r = this.cache.createRegion(getUniqueName(), af.create()); CacheTransactionManager mgr = this.cache.getCacheTransactionManager(); r.put(1, "value1"); r.put(2, "value2"); assertEquals(2, r.size()); mgr.begin(); r.put(3, "value3"); r.destroy(3); mgr.commit(); assertEquals(2, r.size()); } private String getUniqueName() { return getClass().getSimpleName() + "_" + testName.getMethodName(); } private static class TransactionListenerForRegionTest extends TransactionListenerAdapter { private boolean exceptionOccurred = false; @Override public void afterCommit(TransactionEvent event) { List<CacheEvent<?, ?>> events = event.getEvents(); for (CacheEvent<?, ?> e : events) { if (!"/testTxEventForRegion".equals(e.getRegion().getFullPath())) { exceptionOccurred = true; } } } } private static class CacheListenerForRegionTest extends CacheListenerAdapter { private boolean exceptionOccurred = false; @Override public void afterCreate(EntryEvent event) { verifyRegion(event); } @Override public void afterUpdate(EntryEvent event) { verifyRegion(event); } private void verifyRegion(EntryEvent event) { if (!"/testTxEventForRegion".equals(event.getRegion().getFullPath())) { exceptionOccurred = true; } } } }