CLOUDSTACK-9595: Avoiding the deadlocks in the code (#1762)

MySQLTransactionRollbackException is seen frequently in logs
Root Cause
Attempts to lock rows in the core data access layer of database fails if there is a possibility of deadlock. However Operations are not getting retried in case of deadlock. So introducing retries here
Solution
Operations would be retried after some wait time in case of dead lock exception.
This commit is contained in:
subhash yedugundla 2017-12-19 00:06:21 +05:30 committed by Rohit Yadav
parent 3c6df7c970
commit 1edb3e8a45
2 changed files with 66 additions and 63 deletions

View File

@ -553,7 +553,6 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
public List<HostVO> findAndUpdateDirectAgentToLoad(long lastPingSecondsAfter, Long limit, long managementServerId) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
if (s_logger.isDebugEnabled()) {
s_logger.debug("Resetting hosts suitable for reconnect");
}
@ -569,6 +568,7 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
s_logger.debug("Acquiring hosts for clusters already owned by this management server");
}
List<Long> clusters = findClustersOwnedByManagementServer(managementServerId);
txn.start();
if (clusters.size() > 0) {
// handle clusters already owned by @managementServerId
SearchCriteria<HostVO> sc = UnmanagedDirectConnectSearch.create();

View File

@ -291,6 +291,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
SearchBuilder<IPAddressVO> AssignIpAddressSearch;
SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
private final Object _allocatedLock = new Object();
private final Object _allocatingLock = new Object();
static Boolean rulesContinueOnErrFlag = true;
@ -759,7 +761,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l);
List<IPAddressVO> addrs = _ipAddressDao.lockRows(sc, filter, true);
List<IPAddressVO> addrs = _ipAddressDao.search(sc, filter, false);
// If all the dedicated IPs of the owner are in use fetch an IP from the system pool
if (addrs.size() == 0 && fetchFromDedicatedRange) {
@ -769,7 +771,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
fetchFromDedicatedRange = false;
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
addrs = _ipAddressDao.lockRows(sc, filter, true);
addrs = _ipAddressDao.search(sc, filter, false);
}
}
@ -804,24 +806,21 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId());
addr.setSystem(isSystem);
if (displayIp != null) {
addr.setDisplay(displayIp);
}
if (assign) {
markPublicIpAsAllocated(addr);
} else {
addr.setState(IpAddress.State.Allocating);
}
addr.setState(assign ? IpAddress.State.Allocated : IpAddress.State.Allocating);
if (vlanUse != VlanType.DirectAttached) {
addr.setAssociatedWithNetworkId(guestNetworkId);
addr.setVpcId(vpcId);
}
_ipAddressDao.update(addr.getId(), addr);
if (assign) {
markPublicIpAsAllocated(addr);
} else {
markPublicIpAsAllocating(addr);
}
return addr;
}
});
@ -836,17 +835,16 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
@DB
@Override
public void markPublicIpAsAllocated(final IPAddressVO addr) {
synchronized (_allocatedLock) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId());
synchronized (this) {
if (_ipAddressDao.lockRow(addr.getId(), true) != null) {
IPAddressVO userIp = _ipAddressDao.findById(addr.getId());
if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free) {
addr.setState(IpAddress.State.Allocated);
_ipAddressDao.update(addr.getId(), addr);
if (_ipAddressDao.update(addr.getId(), addr)) {
// Save usage event
if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
VlanVO vlan = _vlanDao.findById(addr.getVlanId());
@ -866,6 +864,23 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
}
});
}
}
@DB
private void markPublicIpAsAllocating(final IPAddressVO addr) {
synchronized (_allocatingLock) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
if (_ipAddressDao.lockRow(addr.getId(), true) != null) {
addr.setState(IpAddress.State.Allocating);
_ipAddressDao.update(addr.getId(), addr);
}
}
});
}
}
private boolean isIpDedicated(IPAddressVO addr) {
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId());
@ -901,12 +916,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
PublicIp ip = null;
try {
ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() {
@Override
public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
Account owner = _accountDao.acquireInLockTable(ownerId);
Account ownerAccount = _accountDao.acquireInLockTable(ownerId);
if (owner == null) {
if (ownerAccount == null) {
// this ownerId comes from owner or type Account. See the class "AccountVO" and the annotations in that class
// to get the table name and field name that is queried to fill this ownerid.
ConcurrentOperationException ex = new ConcurrentOperationException("Unable to lock account");
@ -924,17 +936,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
displayIp = vpc.isDisplay();
}
PublicIp ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId, displayIp);
IPAddressVO publicIp = ip.ip();
return fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId, displayIp);
markPublicIpAsAllocated(publicIp);
_ipAddressDao.update(publicIp.getId(), publicIp);
return ip;
}
});
return ip;
} finally {
if (owner != null) {
if (s_logger.isDebugEnabled()) {