blob: 4183d97dbc41d9fe3449c96177e30d30c8644bfb [file] [log] [blame]
/*
* 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 static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import javax.transaction.Synchronization;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.AttributesMutator;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheEvent;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheLoaderException;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.CacheWriter;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.CommitConflictException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.DiskStoreFactory;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.EntryExistsException;
import org.apache.geode.cache.EntryNotFoundException;
import org.apache.geode.cache.EvictionAction;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.FailedSynchronizationException;
import org.apache.geode.cache.LoaderHelper;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionEvent;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.TransactionEvent;
import org.apache.geode.cache.TransactionException;
import org.apache.geode.cache.TransactionId;
import org.apache.geode.cache.TransactionListener;
import org.apache.geode.cache.UnsupportedOperationInTransactionException;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
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.cache.util.TxEventTestUtil;
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.AbstractRegion;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.cache.LocalRegion;
import org.apache.geode.internal.cache.NonTXEntry;
import org.apache.geode.internal.cache.PartitionedRegion;
import org.apache.geode.internal.cache.TXManagerImpl;
import org.apache.geode.internal.cache.TXStateProxy;
import org.apache.geode.internal.util.StopWatch;
import org.apache.geode.logging.internal.log4j.api.LogService;
/**
* Tests basic transaction functionality
*
* @since GemFire 4.0
*/
@SuppressWarnings("deprecated")
public class TXJUnitTest {
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<String, String> region;
@Rule
public TestName testName = new TestName();
private boolean isPR() {
return (this.region instanceof PartitionedRegion);
}
protected void createCache() throws Exception {
Properties properties = new Properties();
properties.setProperty(MCAST_PORT, "0"); // loner
this.cache = (GemFireCacheImpl) CacheFactory.create(DistributedSystem.connect(properties));
createRegion();
this.txMgr = this.cache.getCacheTransactionManager();
this.listenerAfterCommit = 0;
this.listenerAfterFailedCommit = 0;
this.listenerAfterRollback = 0;
this.listenerClose = 0;
}
protected void createRegion() throws Exception {
region = createRegion(getClass().getSimpleName(), false);
}
protected Region createRegion(String regionName, boolean isConcurrencyChecksEnabled)
throws Exception {
AttributesFactory<String, String> attributesFactory = new AttributesFactory<>();
attributesFactory
.setDataPolicy(isConcurrencyChecksEnabled ? DataPolicy.REPLICATE : DataPolicy.NORMAL);
attributesFactory
.setScope(isConcurrencyChecksEnabled ? Scope.DISTRIBUTED_ACK : Scope.DISTRIBUTED_NO_ACK);
attributesFactory.setConcurrencyChecksEnabled(isConcurrencyChecksEnabled); // test validation
// expects this
// behavior
attributesFactory.setIndexMaintenanceSynchronous(true);
return this.cache.createRegion(regionName, attributesFactory.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 setUpTXJUnitTest() throws Exception {
createCache();
}
@After
public void tearDownTXJUnitTest() 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<String, String> attributesFactory = new AttributesFactory<>();
attributesFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
Region<String, String> reg1 = this.region;
Region<String, String> reg2 =
this.cache.createRegion(getUniqueName(), attributesFactory.create());
this.txMgr.setListener(new TransactionListener() {
@Override
public void afterCommit(TransactionEvent event) {
listenerAfterCommit = 1;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
listenerAfterFailedCommit = 1;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
listenerAfterRollback = 1;
te = event;
}
@Override
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());
{
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(2, creates.size());
for (EntryEvent ev : creates) {
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());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().isDistributed());
}
}
reg1.localDestroy("key1");
reg2.localDestroy("key2");
reg2.localDestroyRegion();
}
@Test
public void testTxEvent() throws CacheException {
TransactionId myTxId;
Region<String, String> reg1 = this.region;
this.txMgr.setListener(new TransactionListener() {
@Override
public void afterCommit(TransactionEvent event) {
listenerAfterCommit = 1;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
listenerAfterFailedCommit = 1;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
listenerAfterRollback = 1;
te = event;
}
@Override
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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates = TxEventTestUtil.getPutEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value0", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
if (!isPR())
assertTrue(!ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
{
Cache teCache = this.te.getCache();
assertEquals(teCache, this.cache);
List<EntryEvent<?, ?>> creates =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, creates.size());
for (EntryEvent ev : creates) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
if (!isPR())
assertTrue(!ev.getOperation().isDistributed());
}
}
reg1.localDestroy("key1");
}
private static class CountingCallBackValidator {
List<Object> 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(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(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(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(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(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(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(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(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(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;
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 interface CountingCacheListener extends CacheListener {
int getAfterCreateCalls();
int getAfterUpdateCalls();
int getAfterInvalidateCalls();
int getAfterDestroyCalls(boolean fetchLocal);
void reset();
}
private interface CountingCacheWriter extends CacheWriter {
int getBeforeCreateCalls();
int getBeforeUpdateCalls();
int getBeforeDestroyCalls(boolean fetchLocal);
void reset();
}
@Test
public void testTxAlgebra() throws CacheException {
TransactionId myTxId;
Region<String, String> reg1 = this.region;
this.txMgr.setListener(new TransactionListener() {
@Override
public void afterCommit(TransactionEvent event) {
listenerAfterCommit = 1;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
listenerAfterFailedCommit = 1;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
listenerAfterRollback = 1;
te = event;
}
@Override
public void close() {
listenerClose = 1;
}
});
AttributesMutator<String, String> mutator = this.region.getAttributesMutator();
CountingCacheListener cntListener = new CountingCacheListener() {
volatile int aCreateCalls, aUpdateCalls, aInvalidateCalls, aDestroyCalls, aLocalDestroyCalls;
@Override
public void close() {}
@Override
public void reset() {
this.aCreateCalls = this.aUpdateCalls =
this.aInvalidateCalls = this.aDestroyCalls = this.aLocalDestroyCalls = 0;
}
@Override
public void afterCreate(EntryEvent e) {
++this.aCreateCalls;
}
@Override
public void afterUpdate(EntryEvent e) {
++this.aUpdateCalls;
}
@Override
public void afterInvalidate(EntryEvent e) {
++this.aInvalidateCalls;
}
@Override
public void afterDestroy(EntryEvent e) {
if (e.getOperation().isDistributed()) {
++this.aDestroyCalls;
} else {
++this.aLocalDestroyCalls;
}
}
@Override
public void afterRegionInvalidate(RegionEvent e) {
fail("Unexpected afterRegionInvalidate in testTxAlgebra");
}
@Override
public void afterRegionDestroy(RegionEvent e) {
if (!e.getOperation().isClose()) {
fail("Unexpected afterRegionDestroy in testTxAlgebra");
}
}
@Override
public void afterRegionClear(RegionEvent event) {}
@Override
public void afterRegionCreate(RegionEvent event) {}
@Override
public void afterRegionLive(RegionEvent event) {}
@Override
public int getAfterCreateCalls() {
return this.aCreateCalls;
}
@Override
public int getAfterUpdateCalls() {
return this.aUpdateCalls;
}
@Override
public int getAfterInvalidateCalls() {
return this.aInvalidateCalls;
}
@Override
public int getAfterDestroyCalls(boolean fetchLocal) {
return fetchLocal ? this.aLocalDestroyCalls : this.aDestroyCalls;
}
};
mutator.addCacheListener(cntListener);
CountingCacheWriter cntWriter = new CountingCacheWriter() {
int bCreateCalls, bUpdateCalls, bDestroyCalls, bLocalDestroyCalls;
@Override
public void close() {}
@Override
public void reset() {
this.bCreateCalls = this.bUpdateCalls = this.bDestroyCalls = this.bLocalDestroyCalls = 0;
}
@Override
public void beforeCreate(EntryEvent e) {
++this.bCreateCalls;
}
@Override
public void beforeUpdate(EntryEvent e) {
++this.bUpdateCalls;
}
@Override
public void beforeDestroy(EntryEvent e) {
++this.bDestroyCalls;
}
@Override
public void beforeRegionDestroy(RegionEvent e) {
fail("Unexpected beforeRegionDestroy in testTxAlgebra");
}
@Override
public void beforeRegionClear(RegionEvent e) {
fail("Unexpected beforeRegionClear in testTxAlgebra");
}
@Override
public int getBeforeCreateCalls() {
return this.bCreateCalls;
}
@Override
public int getBeforeUpdateCalls() {
return this.bUpdateCalls;
}
@Override
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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value2", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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();
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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value2", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().isDistributed());
}
}
reg1.localDestroy("key1");
// Check C + LI + LD -> NOOP
callbackVal.reset();
this.txMgr.begin();
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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(0, this.te.getEvents().size());
// Check C + LI + DD -> NOOP
callbackVal.reset();
this.txMgr.begin();
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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(0, this.te.getEvents().size());
// check C + LD -> NOOP
callbackVal.reset();
this.txMgr.begin();
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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events = TxEventTestUtil.getPutEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events = TxEventTestUtil.getPutEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value2", ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events = TxEventTestUtil.getPutEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value2", ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events = TxEventTestUtil.getPutEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value2", ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getDestroyEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals(null, ev.getNewValue());
assertEquals("value0", ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value3", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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
NonTXEntry nonTXe = (NonTXEntry) reg1.getEntry("key1");
assertTrue(nonTXe.getRegionEntry().isInvalid());
}
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertNull(ev.getNewValue());
assertNull(ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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
NonTXEntry nonTXe = (NonTXEntry) reg1.getEntry("key1");
assertTrue(nonTXe.getRegionEntry().isInvalid());
}
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getInvalidateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertNull(ev.getNewValue());
assertNull(ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(!ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(1, this.te.getEvents().size());
{
List<EntryEvent<?, ?>> events =
TxEventTestUtil.getCreateEvents(this.te.getEvents());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(1, events.size());
for (EntryEvent ev : events) {
assertEquals(myTxId, ev.getTransactionId());
assertTrue(ev.getRegion() == reg1);
assertEquals("key1", ev.getKey());
assertEquals("value1", ev.getNewValue());
assertEquals(null, ev.getOldValue());
verifyEventProps(ev);
assertEquals(null, ev.getCallbackArgument());
assertEquals(true, ev.isCallbackArgumentAvailable());
assertTrue(!ev.isOriginRemote());
assertTrue(!ev.getOperation().isExpiration());
assertTrue(ev.getOperation().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() {
@Override
public void afterCommit(TransactionEvent event) {
listenerAfterCommit = 1;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
listenerAfterFailedCommit = 1;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
listenerAfterRollback = 1;
te = event;
}
@Override
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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).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, TxEventTestUtil.getCreateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getPutEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getInvalidateEvents(this.te.getEvents()).size());
assertEquals(0, TxEventTestUtil.getDestroyEvents(this.te.getEvents()).size());
assertEquals(0, this.te.getEvents().size());
assertEquals(myTxId, this.te.getTransactionId());
assertEquals(0, this.listenerClose);
oldListener = this.txMgr.setListener(new TransactionListener() {
@Override
public void afterCommit(TransactionEvent event) {
listenerAfterCommit = 2;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
listenerAfterFailedCommit = 2;
}
@Override
public void afterRollback(TransactionEvent event) {
listenerAfterRollback = 2;
te = event;
}
@Override
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<String, String> mutator = this.region.getAttributesMutator();
mutator.addCacheListener(new CacheListenerAdapter<String, String>() {
@Override
public void close() {
cbCount++;
}
@Override
public void afterCreate(EntryEvent event) {
cbCount++;
}
@Override
public void afterUpdate(EntryEvent event) {
cbCount++;
}
@Override
public void afterInvalidate(EntryEvent event) {
cbCount++;
}
@Override
public void afterDestroy(EntryEvent event) {
cbCount++;
}
@Override
public void afterRegionInvalidate(RegionEvent event) {
cbCount++;
}
@Override
public void afterRegionDestroy(RegionEvent event) {
cbCount++;
}
});
mutator.setCacheWriter(new CacheWriter<String, String>() {
@Override
public void close() {
cbCount++;
}
@Override
public void beforeUpdate(EntryEvent event) throws CacheWriterException {
cbCount++;
}
@Override
public void beforeCreate(EntryEvent event) throws CacheWriterException {
cbCount++;
}
@Override
public void beforeDestroy(EntryEvent event) throws CacheWriterException {
cbCount++;
}
@Override
public void beforeRegionDestroy(RegionEvent event) throws CacheWriterException {
cbCount++;
}
@Override
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.getOperation().isExpiration());
assertTrue(!event.getOperation().isNetLoad());
assertEquals("isLoad Assertion!", this.isLoad(), event.getOperation().isLoad());
assertEquals("isLocalLoad Assertion!", this.isLoad(), event.getOperation().isLocalLoad());
assertTrue(!event.getOperation().isNetSearch());
assertTrue(!event.isOriginRemote());
assertNotNull(event.getRegion());
assertNotNull(event.getRegion().getCache());
assertNotNull(event.getRegion().getCache().getCacheTransactionManager());
assertEquals(this.getTXId(), event.getTransactionId());
if (!isPR())
assertEquals("IsDistributed Assertion!", this.isDistributed(),
event.getOperation().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;
}
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 interface ValidatableCacheListener extends CacheListener {
void setValidator(TXCallBackValidator v);
void validate();
void validateNoEvents();
void reset();
void setExpectedCount(int count);
int getCallCount();
}
private interface ValidatableCacheWriter extends CacheWriter {
void setValidator(TXCallBackValidator v);
int getCallCount();
void localDestroyMakeup(int count);
void validate();
void reset();
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<String, String> mutator = this.region.getAttributesMutator();
TXCallBackValidator cbv = new TXCallBackValidator();
// Cache Listener
ValidatableCacheListener vCl = new ValidatableCacheListener() {
TXCallBackValidator v;
int callCount;
int prevCallCount;
EntryEvent lastEvent;
@Override
public void validate() {
this.v.validate(this.lastEvent, this.callCount);
}
void validate(EntryEvent event) {
this.v.validate(event, ++this.callCount);
}
@Override
public void setValidator(TXCallBackValidator v) {
this.v = v;
}
@Override
public void close() {}
@Override
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);
}
@Override
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);
}
@Override
public void afterInvalidate(EntryEvent event) {
lastEvent = event;
if (this.v.isSuspendValidation()) {
return;
}
validate(event);
this.v.setPassedValidation(false);
assertTrue("IsInvalidate 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);
}
@Override
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);
}
@Override
public void afterRegionInvalidate(RegionEvent event) {
fail("Unexpected invocation of afterRegionInvalidate");
}
@Override
public void afterRegionDestroy(RegionEvent event) {
if (!event.getOperation().isClose()) {
fail("Unexpected invocation of afterRegionDestroy");
}
}
@Override
public void afterRegionClear(RegionEvent event) {}
@Override
public void afterRegionCreate(RegionEvent event) {}
@Override
public void afterRegionLive(RegionEvent event) {}
@Override
public void reset() {
lastEvent = null;
prevCallCount = callCount;
}
@Override
public void validateNoEvents() {
assertNull("Did not expect listener callback", lastEvent);
assertEquals(prevCallCount, callCount);
}
@Override
public void setExpectedCount(int count) {
callCount = count;
}
@Override
public int getCallCount() {
return callCount;
}
};
vCl.setValidator(cbv);
mutator.addCacheListener(vCl);
// CacheWriter
ValidatableCacheWriter vCw = new ValidatableCacheWriter() {
TXCallBackValidator v;
int callCount;
int prevCallCount;
EntryEvent lastEvent;
@Override
public int getCallCount() {
return this.callCount;
}
@Override
public void localDestroyMakeup(int count) {
this.callCount += count;
}
@Override
public void validate() {
this.v.validate(this.lastEvent, this.callCount);
}
void validate(EntryEvent event) {
this.v.validate(event, ++this.callCount);
}
@Override
public void setValidator(TXCallBackValidator v) {
this.v = v;
}
@Override
public void close() {}
@Override
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);
}
@Override
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 invalid
// assertTrue(event.getRegion().containsValueForKey(this.v.getKey()));
this.v.setPassedValidation(true);
}
@Override
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);
}
@Override
public void beforeRegionDestroy(RegionEvent event) {
fail("Unexpected invocation of beforeRegionDestroy");
}
@Override
public void beforeRegionClear(RegionEvent event) {
fail("Unexpected invocation of beforeRegionClear");
}
@Override
public void reset() {
lastEvent = null;
prevCallCount = callCount;
}
@Override
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;
@Override
public Object load(LoaderHelper helper) throws CacheLoaderException {
return count++;
}
@Override
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(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(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(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(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(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(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<String, String> reg1 = this.region;
checkSubRegionCollection(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(
String.format(
"The Region collection is not transactional but is being used in a transaction %s.",
txid),
expected.getMessage());
}
assertEquals(1, txKeys.size());
try {
nonTxValues.size();
fail();
} catch (IllegalStateException expected) {
TransactionId txid = this.txMgr.getTransactionId();
assertEquals(
String.format(
"The Region collection is not transactional but is being used in a transaction %s.",
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");
assertEquals(1, txKeys.size());
assertEquals(0, txValues.size());
assertTrue(txKeys.contains("key1"));
assertTrue(!txValues.contains("value1"));
reg1.create("key2", "value2");
reg1.create("key3", "value3");
assertEquals(3, txKeys.size());
assertEquals(2, txValues.size());
reg1.put("key1", "value1");
assertEquals(3, txKeys.size());
assertEquals(3, txValues.size());
reg1.localInvalidate("key2");
assertEquals(2, txValues.size());
reg1.invalidate("key1");
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();
}
{
this.txMgr.begin();
reg1.create("key1", "value1");
Collection txValues = reg1.values();
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(
String.format(
"The Region collection is not transactional but is being used in a transaction %s.",
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());
// non-TX collections can now be used in a transactional context
try {
nonTxValues.iterator().hasNext();
} catch (IllegalStateException expected) {
TransactionId txid = this.txMgr.getTransactionId();
assertEquals(
String.format(
"The Region collection is not transactional but is being used in a transaction %s.",
txid),
expected.getMessage());
}
reg1.localInvalidate("key1");
assertEquals(0, txValues.size());
assertTrue(!txValues.iterator().hasNext());
this.txMgr.rollback();
}
}
protected void checkSubRegionCollection(Region<String, String> reg1) {
AttributesFactory<String, String> attributesFactory = new AttributesFactory<>();
attributesFactory.setScope(Scope.DISTRIBUTED_NO_ACK);
Region<String, String> sub1 =
this.region.createSubregion("collectionSub1", attributesFactory.create());
attributesFactory = new AttributesFactory<>();
Region<String, String> sub2 =
this.region.createSubregion("collectionSub2", attributesFactory.create());
attributesFactory = new AttributesFactory<>();
attributesFactory.setScope(Scope.LOCAL);
Region<String, String> sub2_1 =
sub2.createSubregion("collectionSub2_1", attributesFactory.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);
reg1.localDestroy("key1");
reg1.localDestroy("key3");
checkCollectionSize(0);
}
@Test
public void testLoader() throws CacheException {
AttributesMutator<String, String> mutator = this.region.getAttributesMutator();
mutator.setCacheLoader(new CacheLoader<String, String>() {
int count = 0;
@Override
public String load(LoaderHelper helper) throws CacheLoaderException {
count++;
return "LV " + count;
}
@Override
public void close() {}
});
LocalRegion reg1 = (LocalRegion) this.region;
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.pauseTransaction();
assertTrue(!reg1.containsKey("key1"));
assertEquals("LV 4", reg1.get("key1"));
assertTrue(reg1.containsKey("key1"));
txMgrImpl.unpauseTransaction(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.pauseTransaction();
assertTrue(!reg1.containsKey("key1"));
reg1.create("key1", "txValue");
assertTrue(reg1.containsKey("key1"));
assertEquals("txValue", reg1.get("key1"));
txMgrImpl.unpauseTransaction(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;
TransactionId txId = null;
this.txMgr.begin();
reg1.create("key1", "txValue");
txId = txMgrImpl.suspend();
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(txId);
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 {
private long txSuccessLifeTime;
private long txFailedLifeTime;
private long txRollbackLifeTime;
private int txCommits;
private int txFailures;
private int txRollbacks;
private long txCommitTime;
private long txFailureTime;
private long txRollbackTime;
private int txCommitChanges;
private int txFailureChanges;
private int txRollbackChanges;
private CachePerfStats stats;
private statsValidator(CachePerfStats stats) {
this.stats = stats;
}
private 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();
}
private void setTxSuccessLifeTime(long txSuccessLifeTime) {
this.txSuccessLifeTime = txSuccessLifeTime;
}
private void setTxFailedLifeTime(long txFailedLifeTime) {
this.txFailedLifeTime = txFailedLifeTime;
}
private void setTxRollbackLifeTime(long txRollbackLifeTime) {
this.txRollbackLifeTime = txRollbackLifeTime;
}
private void setTxCommits(int txCommits) {
this.txCommits = txCommits;
}
private void setTxFailures(int txFailures) {
this.txFailures = txFailures;
}
private void setTxRollbacks(int txRollbacks) {
this.txRollbacks = txRollbacks;
}
private void setTxCommitTime(long txCommitTime) {
this.txCommitTime = txCommitTime;
}
private void setTxFailureTime(long txFailureTime) {
this.txFailureTime = txFailureTime;
}
private void setTxRollbackTime(long txRollbackTime) {
this.txRollbackTime = txRollbackTime;
}
private void setTxCommitChanges(int txCommitChanges) {
this.txCommitChanges = txCommitChanges;
}
private void setTxFailureChanges(int txFailureChanges) {
this.txFailureChanges = txFailureChanges;
}
private void setTxRollbackChanges(int txRollbackChanges) {
this.txRollbackChanges = txRollbackChanges;
}
private 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.pauseTransaction();
this.region.put("stats1", "stats success1");
this.region.put("stats2", "stats success2");
txMgrImpl.unpauseTransaction(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
long creates;
long destroys;
long puts;
long 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 testPauseUnpause() {
TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr;
assertTrue(!this.txMgr.exists());
assertEquals(null, txMgrImpl.pauseTransaction());
TXStateProxy txProxy = null;
txMgrImpl.unpauseTransaction(txProxy);
assertTrue(!this.txMgr.exists());
this.txMgr.begin();
TransactionId origId = this.txMgr.getTransactionId();
assertTrue(this.txMgr.exists());
{
TXStateProxy tx = txMgrImpl.pauseTransaction();
assertTrue(!this.txMgr.exists());
assertThatThrownBy(() -> this.txMgr.begin()).isInstanceOf(IllegalStateException.class);
assertTrue(!this.txMgr.exists());
txMgrImpl.unpauseTransaction(tx);
}
assertTrue(this.txMgr.exists());
assertEquals(origId, this.txMgr.getTransactionId());
this.txMgr.rollback();
}
@Test
public void testSuspendResume() {
TXManagerImpl txMgrImpl = (TXManagerImpl) this.txMgr;
assertTrue(!this.txMgr.exists());
assertEquals(null, txMgrImpl.pauseTransaction());
TXStateProxy txProxy = null;
txMgrImpl.unpauseTransaction(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.internalResume(tx);
fail("expected IllegalStateException");
} catch (IllegalStateException expected) {
LogService.getLogger().info("expected ", expected);
}
this.txMgr.rollback();
assertTrue(!this.txMgr.exists());
txMgrImpl.internalResume(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<String, String> af = new AttributesFactory<>();
af.setScope(Scope.GLOBAL);
Region<String, String> 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<String, String> af = new AttributesFactory<>();
af.setScope(Scope.LOCAL);
af.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE);
af.setDiskStoreName("testCheckNoTX");
Region<String, String> 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 valuesRepeatableReadDoesNotIncludeTombstones() throws Exception {
Region newRegion = createRegion("newRegion", true);
newRegion.put("key1", "value1");
newRegion.destroy("key1"); // creates a tombstone
txMgr.begin(); // tx1
newRegion.values().toArray(); // this is a repeatable read, does not read tombstone
TransactionId txId = txMgr.suspend();
txMgr.begin(); // tx2
newRegion.put("key1", "newValue");
txMgr.commit();
txMgr.resume(txId);
newRegion.put("key1", "value1");
txMgr.commit();
assertThat(newRegion.get("key1")).isEqualTo("value1");
}
@Test
public void keySetRepeatableReadDoesNotIncludeTombstones() throws Exception {
Region newRegion = createRegion("newRegion", true);
newRegion.put("key1", "value1");
newRegion.destroy("key1"); // creates a tombstone
txMgr.begin(); // tx1
newRegion.keySet().toArray(); // this is a repeatable read, does not read tombstone
TransactionId txId = txMgr.suspend();
txMgr.begin(); // tx2
newRegion.put("key1", "newValue");
txMgr.commit();
txMgr.resume(txId);
newRegion.put("key1", "value1");
txMgr.commit();
assertThat(newRegion.get("key1")).isEqualTo("value1");
}
@Test
public void valuesRepeatableReadIncludesInvalidates() throws Exception {
Region newRegion = createRegion("newRegion", true);
newRegion.put("key1", "value1");
newRegion.invalidate("key1");
txMgr.begin(); // tx1
newRegion.values().toArray(); // this is a repeatable read, reads invalidate
TransactionId txId = txMgr.suspend();
txMgr.begin(); // tx2
newRegion.put("key1", "newValue");
txMgr.commit();
txMgr.resume(txId);
newRegion.put("key1", "value1");
assertThatThrownBy(() -> txMgr.commit()).isExactlyInstanceOf(CommitConflictException.class);
assertThat(newRegion.get("key1")).isEqualTo("newValue");
}
@Test
public void keySetRepeatableReadIncludesInvalidates() throws Exception {
Region newRegion = createRegion("newRegion", true);
newRegion.put("key1", "value1");
newRegion.invalidate("key1");
txMgr.begin(); // tx1
newRegion.keySet().toArray(); // this is a repeatable read, reads invalidate
TransactionId txId = txMgr.suspend();
txMgr.begin(); // tx2
newRegion.put("key1", "newValue");
txMgr.commit();
txMgr.resume(txId);
newRegion.put("key1", "value1");
assertThatThrownBy(() -> txMgr.commit()).isExactlyInstanceOf(CommitConflictException.class);
assertThat(newRegion.get("key1")).isEqualTo("newValue");
}
@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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.create("key1", "value1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.remove("key1"); // non-tx
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.create("newKey", "valueNONTX");
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.create("newKey", "valueNONTX");
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.put("key1", "value2"); // do a non-tx put to force conflict
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.invalidate("key1");
txMgrImpl.unpauseTransaction(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.pauseTransaction();
this.region.localDestroyRegion(); // non-tx
txMgrImpl.unpauseTransaction(tis);
try {
txMgrImpl.commit();
fail("expected CommitConflictException");
} catch (TransactionException ex) {
}
}
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");
}
}
private 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");
}
}
private static final int LRUENTRY_NULL = 0;
private static final int LRUENTRY_STRING = 1;
private static final int LRUENTRY_INTEGER = 2;
private static final int LRUENTRY_LONG = 3;
private static final int LRUENTRY_DOUBLE = 4;
private 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<String, Object> af = new AttributesFactory<>();
af.setEvictionAttributes(
EvictionAttributes.createLRUEntryAttributes(lruSize, EvictionAction.LOCAL_DESTROY));
af.setScope(Scope.LOCAL);
Region<String, Object> 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.pauseTransaction();
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.unpauseTransaction(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<String, Object> mutator = lruRegion.getAttributesMutator();
mutator.setCacheLoader(new CacheLoader() {
// int count = 0;
@Override
public Object load(LoaderHelper helper) throws CacheLoaderException {
return "value" + helper.getArgument();
}
@Override
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.pauseTransaction();
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.unpauseTransaction(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;
TransactionId txId1, txId2;
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);
txId1 = txMgrImpl.suspend();
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);
txId2 = txMgrImpl.suspend();
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));
}
assertTrue(numToPut > lruSize);
assertNull(lruRegion.get("non-tx key0"));
assertLRUEntries(lruRegion.entrySet(false), lruSize, "key", LRUENTRY_INTEGER);
txMgrImpl.resume(txId1);
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(txId2);
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.pauseTransaction();
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.unpauseTransaction(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.pauseTransaction();
// Cause a conflict
lruRegion.put("key" + (numToPut - 1), new Integer(numToPut - 1));
txMgrImpl.unpauseTransaction(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() {
@Override
public void afterCommit(TransactionEvent event) {
++listenerAfterCommit;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
++listenerAfterFailedCommit;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
++listenerAfterRollback;
te = event;
}
@Override
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.pauseTransaction();
javax.transaction.Transaction jtaTx = jtaTxMgr.suspend();
assertNull(jtaTxMgr.getTransaction());
this.region.put("syncKey3", "syncVal4");
assertEquals("syncVal4", this.region.getEntry("syncKey3").getValue());
gfTxMgrImpl.unpauseTransaction(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") {
@Override
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() {
@Override
public void afterCommit(TransactionEvent event) {
++listenerAfterCommit;
te = event;
}
@Override
public void afterFailedCommit(TransactionEvent event) {
++listenerAfterFailedCommit;
te = event;
}
@Override
public void afterRollback(TransactionEvent event) {
++listenerAfterRollback;
te = event;
}
@Override
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 enlistment 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 enlistment 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 enlistment 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 enlistment 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 enlistment 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<String, String> mutator = this.region.getAttributesMutator();
mutator.setCacheLoader(new CacheLoader<String, String>() {
int count = 0;
@Override
public String load(LoaderHelper helper) throws CacheLoaderException {
return String.valueOf(count++);
}
@Override
public void close() {}
});
assertEquals(4, this.listenerAfterCommit);
userTx.begin();
assertEquals("0", this.region.get("enlistKey"));
assertNotNull(this.txMgr.getTransactionId());
userTx.commit();
assertNull(this.txMgr.getTransactionId());
assertTrue(this.region.containsKey("enlistKey"));
assertEquals("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.pauseTransaction();
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.unpauseTransaction(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
*
*/
@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
*
*/
@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.pauseTransaction();
assertTrue(!pr.containsKey("stuff"));
assertTrue(!r.containsKey("stuff"));
ctm.unpauseTransaction(tx);
ctm.commit();
assertTrue(pr.containsKey("stuff"));
assertTrue(r.containsKey("stuff"));
}
/**
* make sure that we throw an UnsupportedOperationInTransactionException
*
*/
@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
*
*/
@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
*
*/
@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
*
*/
@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;
}
}
}
private void verifyEventProps(EntryEvent ev) {
assertTrue(!ev.getOperation().isLocalLoad());
assertTrue(!ev.getOperation().isNetLoad());
assertTrue(!ev.getOperation().isLoad());
assertTrue(!ev.getOperation().isNetSearch());
}
private enum OperationType {
REPLACE, REMOVE
}
@Test
public void removeShouldNotCleanupRepeatableReadTXEntriesIfEntryNotFound() {
repeatableReadTXEntriesShouldNotBeCleanedUpIfEntryNotFound(OperationType.REMOVE);
}
@Test
public void replaceShouldNotCleanupRepeatableReadTXEntriesIfEntryNotFound() {
repeatableReadTXEntriesShouldNotBeCleanedUpIfEntryNotFound(OperationType.REPLACE);
}
private void repeatableReadTXEntriesShouldNotBeCleanedUpIfEntryNotFound(OperationType type) {
RegionFactory regionFactory = cache.createRegionFactory(RegionShortcut.REPLICATE);
Region<Integer, String> region = regionFactory.create(getUniqueName());
region.put(1, "value1");
region.put(2, "value2");
txMgr.begin();
region.put(1, "newValue1");
TransactionId transaction1 = txMgr.suspend();
txMgr.begin();
region.get(1); // a repeatable read operation
switch (type) {
case REMOVE:
assertThat(region.remove(2, "nonExistingValue")).isFalse();
break;
case REPLACE:
assertThat(region.replace(2, "newValue", "nonExistingValue")).isFalse();
break;
default:
throw new RuntimeException("Unknown operation");
};
TransactionId transaction2 = txMgr.suspend();
txMgr.resume(transaction1);
txMgr.commit();
txMgr.resume(transaction2);
region.put(1, "anotherValue");
assertThatThrownBy(() -> txMgr.commit()).isInstanceOf(CommitConflictException.class);
}
}