use of org.apache.geode.cache.TransactionDataRebalancedException in project geode by apache.
the class TXState method lockBucketRegions.
protected void lockBucketRegions() throws PrimaryBucketException {
boolean lockingSucceeded;
do {
lockingSucceeded = true;
Iterator<Map.Entry<LocalRegion, TXRegionState>> it = this.regions.entrySet().iterator();
Set<BucketRegion> obtained = new HashSet<BucketRegion>();
while (it.hasNext()) {
Map.Entry<LocalRegion, TXRegionState> me = it.next();
LocalRegion r = me.getKey();
if (r instanceof BucketRegion && (((BucketRegion) r).getBucketAdvisor().isPrimary())) {
BucketRegion b = (BucketRegion) r;
/*
* Lock the primary bucket so it doesnt get rebalanced until we cleanup!
*/
boolean lockObtained = false;
try {
// use tryLocks to avoid hanging (bug #41708)
boolean locked = b.doLockForPrimary(true);
if (locked) {
obtained.add(b);
lockObtained = true;
} else {
// if we can't get locks then someone has a write-lock. To prevent
// deadlock (see bug #41708) we release locks and re-acquire them
r.getCancelCriterion().checkCancelInProgress(null);
if (logger.isDebugEnabled()) {
logger.debug("tryLock failed for commit on {}. Releasing locks and retrying", r.getFullPath());
}
// release locks and start over
break;
}
} catch (RegionDestroyedException rde) {
if (logger.isDebugEnabled()) {
logger.debug("RegionDestroyedException while locking bucket region {}", r.getFullPath(), rde);
}
throw new TransactionDataRebalancedException("Bucket rebalanced during commit: " + r.getFullPath());
} finally {
if (!lockObtained) {
// fix for bug #41708 - unlock operation-locks already obtained
if (logger.isDebugEnabled()) {
logger.debug("Unexpected exception while locking bucket {}", r.getFullPath());
}
for (BucketRegion br : obtained) {
br.doUnlockForPrimary();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
lockingSucceeded = false;
}
}
}
}
} while (!lockingSucceeded);
gotBucketLocks = true;
}
use of org.apache.geode.cache.TransactionDataRebalancedException in project geode by apache.
the class TXState method commit.
/*
* (non-Javadoc)
*
* @see org.apache.geode.internal.cache.TXStateInterface#commit()
*/
public void commit() throws CommitConflictException {
if (this.closed) {
return;
}
if (logger.isDebugEnabled()) {
logger.debug("committing transaction {}", getTransactionId());
}
synchronized (this.completionGuard) {
this.completionStarted = true;
}
if (onBehalfOfRemoteStub && !proxy.isCommitOnBehalfOfRemoteStub()) {
throw new UnsupportedOperationInTransactionException(LocalizedStrings.TXState_CANNOT_COMMIT_REMOTED_TRANSACTION.toLocalizedString());
}
cleanupNonDirtyRegions();
try {
/*
* Lock buckets so they can't be rebalanced then perform the conflict check to fix #43489
*/
try {
lockBucketRegions();
} catch (PrimaryBucketException pbe) {
// not sure what to do here yet
RuntimeException re = new TransactionDataRebalancedException(LocalizedStrings.PartitionedRegion_TRANSACTIONAL_DATA_MOVED_DUE_TO_REBALANCING.toLocalizedString());
re.initCause(pbe);
throw re;
}
if (this.locks == null) {
reserveAndCheck();
}
// For internal testing
if (this.internalAfterConflictCheck != null) {
this.internalAfterConflictCheck.run();
}
/*
* If there is a TransactionWriter plugged in, we need to to give it an opportunity to abort
* the transaction.
*/
TransactionWriter writer = this.proxy.getTxMgr().getWriter();
if (!firedWriter && writer != null) {
try {
firedWriter = true;
TXEvent event = getEvent();
if (!event.hasOnlyInternalEvents()) {
writer.beforeCommit(event);
}
} catch (TransactionWriterException twe) {
cleanup();
throw new CommitConflictException(twe);
} catch (VirtualMachineError err) {
// cleanup(); this allocates objects so I don't think we can do it - that leaves the TX
// open, but we are poison pilling so we should be ok??
SystemFailure.initiateFailure(err);
// now, so don't let this thread continue.
throw err;
} catch (Throwable t) {
// rollback the transaction!
cleanup();
// Whenever you catch Error or Throwable, you must also
// catch VirtualMachineError (see above). However, there is
// _still_ a possibility that you are dealing with a cascading
// error condition, so you also need to check to see if the JVM
// is still usable:
SystemFailure.checkFailure();
throw new CommitConflictException(t);
}
}
List /* <TXEntryStateWithRegionAndKey> */
entries = generateEventOffsets();
TXCommitMessage msg = null;
try {
/*
* In order to preserve data consistency, we need to: 1. Modify the cache first
* (applyChanges) 2. Ask for advice on who to send to (buildMessage) 3. Send out to other
* members.
*
* If this is done out of order, we will have problems with GII, split brain, and HA. See
* bug #41187
*
* @gregp
*/
attachFilterProfileInformation(entries);
lockTXRegions(regions);
try {
// apply changes to the cache
applyChanges(entries);
// For internal testing
if (this.internalAfterApplyChanges != null) {
this.internalAfterApplyChanges.run();
}
// build and send the message
msg = buildMessage();
this.commitMessage = msg;
if (this.internalBeforeSend != null) {
this.internalBeforeSend.run();
}
msg.send(this.locks.getDistributedLockId());
// For internal testing
if (this.internalAfterSend != null) {
this.internalAfterSend.run();
}
firePendingCallbacks();
/*
* This is to prepare the commit message for the caller, make sure all events are in
* there.
*/
this.commitMessage = buildCompleteMessage();
} finally {
unlockTXRegions(regions);
}
} finally {
if (msg != null) {
msg.releaseViewVersions();
}
this.locks.releaseLocal();
// For internal testing
if (this.internalAfterReleaseLocalLocks != null) {
this.internalAfterReleaseLocalLocks.run();
}
}
} finally {
cleanup();
}
}
use of org.apache.geode.cache.TransactionDataRebalancedException in project geode by apache.
the class TXStateProxyImpl method getEntry.
public Entry getEntry(KeyInfo keyInfo, LocalRegion region, boolean allowTombstones) {
try {
this.operationCount++;
Entry retVal = getRealDeal(keyInfo, region).getEntry(keyInfo, region, allowTombstones);
trackBucketForTx(keyInfo);
return retVal;
} catch (TransactionDataRebalancedException | PrimaryBucketException re) {
throw getTransactionException(keyInfo, re);
}
}
use of org.apache.geode.cache.TransactionDataRebalancedException in project geode by apache.
the class MyTransactionFunction method verifyDestroyOperation.
private void verifyDestroyOperation(RegionFunctionContext ctx) {
Region custPR = ctx.getDataSet();
Region orderPR = custPR.getCache().getRegion(PRColocationDUnitTest.OrderPartitionedRegionName);
CacheTransactionManager mgr = custPR.getCache().getCacheTransactionManager();
ArrayList args = (ArrayList) ctx.getArguments();
CustId custId = (CustId) args.get(1);
Customer newCus = (Customer) args.get(2);
OrderId orderId = (OrderId) args.get(3);
Order order = (Order) args.get(4);
Customer oldCustomer = (Customer) custPR.get(custId);
Customer commitedCust = null;
// test destroy rollback
mgr.begin();
custPR.put(custId, newCus);
custPR.destroy(custId);
orderPR.put(orderId, order);
mgr.rollback();
commitedCust = (Customer) custPR.get(custId);
Assert.assertTrue(oldCustomer.equals(commitedCust), "Expected customer to rollback to:" + oldCustomer + " but was:" + commitedCust);
// test destroy rollback on unmodified entry
mgr.begin();
custPR.destroy(custId);
orderPR.put(orderId, order);
mgr.rollback();
commitedCust = (Customer) custPR.get(custId);
Assert.assertTrue(oldCustomer.equals(commitedCust), "Expected customer to rollback to:" + oldCustomer + " but was:" + commitedCust);
// test remote destroy
boolean caughtEx = false;
try {
mgr.begin();
Customer cust = new Customer("foo", "bar");
custPR.put(custId, cust);
custPR.destroy(custId);
custPR.putIfAbsent(custId, cust);
custPR.remove(custId, cust);
custPR.destroy(new CustId(1));
custPR.destroy(new CustId(3));
custPR.destroy(new CustId(7));
mgr.commit();
} catch (Exception e) {
mgr.rollback();
if (e instanceof TransactionDataNotColocatedException) {
caughtEx = true;
} else if (e instanceof TransactionDataRebalancedException) {
caughtEx = true;
} else if (e instanceof EntryNotFoundException && e.getMessage().matches("Entry not found for key.*1")) {
caughtEx = true;
} else {
throw new TestException("Expected to catch PR remote destroy exception, but caught:" + e.getMessage(), e);
}
}
if (!caughtEx) {
throw new TestException("An Expected exception was not thrown");
}
// test destroy on unmodified entry
mgr.begin();
custPR.destroy(custId);
orderPR.put(orderId, order);
mgr.commit();
commitedCust = (Customer) custPR.get(custId);
Assert.assertTrue(commitedCust == null, "Expected Customer to be null but was:" + commitedCust);
Order commitedOrder = (Order) orderPR.get(orderId);
Assert.assertTrue(order.equals(commitedOrder), "Expected Order to be:" + order + " but was:" + commitedOrder);
// put the customer again for invalidate verification
mgr.begin();
custPR.putIfAbsent(custId, newCus);
mgr.commit();
// test destroy on new entry
// TODO: This throws EntryNotFound
OrderId newOrderId = new OrderId(5000, custId);
mgr.begin();
Order newOrder = new Order("New Order to be destroyed");
orderPR.put(newOrderId, newOrder);
orderPR.destroy(newOrderId);
mgr.commit();
Assert.assertTrue(orderPR.get(newOrderId) == null, "Did not expect orderId to be present");
// test ConcurrentMap operations
mgr.begin();
Order order1 = new Order("New Order to be replaced");
Order order2 = new Order("New Order to be destroyed");
orderPR.putIfAbsent(newOrderId, order1);
Assert.assertTrue(order1.equals(orderPR.replace(newOrderId, order2)));
// value is order2
mgr.commit();
Assert.assertTrue(order2.equals(orderPR.get(newOrderId)));
mgr.begin();
Assert.assertTrue(orderPR.replace(newOrderId, order2, order1));
// value is order1
mgr.commit();
Assert.assertTrue(orderPR.get(newOrderId).equals(order1));
mgr.begin();
// this should return false since the value is order1
Assert.assertTrue(!orderPR.remove(newOrderId, new Object()));
mgr.commit();
Assert.assertTrue(orderPR.get(newOrderId).equals(order1));
mgr.begin();
Assert.assertTrue(orderPR.remove(newOrderId, order1));
// gone now
mgr.commit();
Assert.assertTrue(orderPR.get(newOrderId) == null);
}
Aggregations