Skip to content

Commit

Permalink
Customized global lock retry interval and lock retry times and optimi…
Browse files Browse the repository at this point in the history
…ze lock retry mechanism. (#370)
  • Loading branch information
zkyoma authored and cherrylzhao committed Oct 24, 2023
1 parent 13ddb58 commit 52dc6ba
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,18 @@
* @return the transaction isolation level enum
*/
IsolationLevelEnum isolationLevel() default IsolationLevelEnum.READ_UNCOMMITTED;

/**
* customized global lock retry interval(unit: ms).
*
* @return lock retry interval
*/
int lockRetryInterval() default 0;

/**
* customized global lock retry times.
*
* @return lock retry times
*/
int lockRetryTimes() default -1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ public class HmilyConfig extends AbstractConfig {
* global lock retry times.
*/
private int lockRetryTimes = 30;

/**
* whether the lock retry policy is enabled.
*/
private boolean lockRetryPolicy = true;

@Override
public String prefix() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ public class HmilyTransactionContext {
*/
private int isolationLevel;

/**
* lock retry interval.
*/
private int lockRetryInterval;

/**
* lock retry times.
*/
private int lockRetryTimes;

//以下为xa相关的参数.
/**
* xa相关的参数定义.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* @author zhangzhi
*/
@Slf4j
public class LockRetryController {
public class HmilyLockRetryHandler {

private int lockRetryInterval;

Expand All @@ -20,10 +20,10 @@ public class LockRetryController {
/**
* Instantiates a new Lock retry controller.
*/
public LockRetryController() {
public HmilyLockRetryHandler(final int lockRetryInterval, final int lockRetryTimes) {
HmilyConfig hmilyConfig = ConfigEnv.getInstance().getConfig(HmilyConfig.class);
this.lockRetryInterval = hmilyConfig.getLockRetryInterval();
this.lockRetryTimes = hmilyConfig.getLockRetryTimes();
this.lockRetryInterval = lockRetryInterval <= 0 ? hmilyConfig.getLockRetryInterval() : lockRetryInterval;
this.lockRetryTimes = lockRetryTimes < 0 ? hmilyConfig.getLockRetryTimes() : lockRetryTimes;
}

/**
Expand All @@ -32,7 +32,6 @@ public LockRetryController() {
* @throws LockWaitTimeoutException the lock wait timeout exception
*/
public void sleep(final Exception e) {
// prioritize the rollback of other transactions
if (--lockRetryTimes < 0) {
log.error("Global lock wait timeout");
throw new LockWaitTimeoutException("Global lock wait timeout", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public HmilyTransaction begin(final ProceedingJoinPoint point) {
Method method = signature.getMethod();
final HmilyTAC hmilyTAC = method.getAnnotation(HmilyTAC.class);
context.setIsolationLevel(hmilyTAC.isolationLevel().getValue());
context.setLockRetryInterval(hmilyTAC.lockRetryInterval());
context.setLockRetryTimes(hmilyTAC.lockRetryTimes());
context.setParticipantId(hmilyParticipant.getParticipantId());
HmilyContextHolder.set(context);
log.debug("TAC-tm-begin ::: {}", globalHmilyTransaction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import org.dromara.hmily.annotation.TransTypeEnum;
import org.dromara.hmily.common.enums.HmilyActionEnum;
import org.dromara.hmily.common.utils.IdWorkerUtils;
import org.dromara.hmily.config.api.ConfigEnv;
import org.dromara.hmily.config.api.entity.HmilyConfig;
import org.dromara.hmily.core.context.HmilyContextHolder;
import org.dromara.hmily.core.context.HmilyTransactionContext;
import org.dromara.hmily.core.repository.HmilyRepositoryStorage;
Expand All @@ -36,7 +38,7 @@
import org.dromara.hmily.tac.core.cache.HmilyUndoContextCacheManager;
import org.dromara.hmily.tac.core.context.HmilyUndoContext;
import org.dromara.hmily.tac.core.lock.HmilyLockManager;
import org.dromara.hmily.tac.core.lock.LockRetryController;
import org.dromara.hmily.tac.core.lock.HmilyLockRetryHandler;
import org.dromara.hmily.tac.p6spy.threadlocal.AutoCommitThreadLocal;
import org.dromara.hmily.tac.sqlcompute.HmilySQLComputeEngine;
import org.dromara.hmily.tac.sqlcompute.HmilySQLComputeEngineFactory;
Expand Down Expand Up @@ -102,40 +104,38 @@ public void execute(final String sql, final List<Object> parameters, final Conne
}
String resourceId = ResourceIdUtils.INSTANCE.getResourceId(connectionInformation.getUrl());
HmilySQLComputeEngine sqlComputeEngine = HmilySQLComputeEngineFactory.newInstance(statement);
// select SQL
HmilyTransactionContext transactionContext = HmilyContextHolder.get();
int lockRetryInterval = transactionContext.getLockRetryInterval();
int lockRetryTimes = transactionContext.getLockRetryTimes();
// select SQL
if (statement instanceof HmilySelectStatement) {
if (IsolationLevelEnum.READ_COMMITTED.getValue() == transactionContext.getIsolationLevel()) {
// read committed level need check locks
executeSelect(sql, parameters, connectionInformation, sqlComputeEngine, resourceId);
executeSelect(sql, parameters, connectionInformation, sqlComputeEngine, resourceId, lockRetryInterval, lockRetryTimes);
}
return;
}
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
log.debug("TAC-compute-sql ::: {}", snapshot);
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
HmilyLockManager.INSTANCE.tryAcquireLocks(undoContext.getHmilyLocks());
log.debug("TAC-try-lock ::: {}", undoContext.getHmilyLocks());
HmilyUndoContextCacheManager.INSTANCE.set(undoContext);
// update delete insert SQL
new HmilyLockRetryPolicy(lockRetryInterval, lockRetryTimes).execute(() -> {
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
log.debug("TAC-compute-sql ::: {}", snapshot);
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
HmilyLockManager.INSTANCE.tryAcquireLocks(undoContext.getHmilyLocks());
log.debug("TAC-try-lock ::: {}", undoContext.getHmilyLocks());
HmilyUndoContextCacheManager.INSTANCE.set(undoContext);
});
}

private void executeSelect(final String sql, final List<Object> parameters, final ConnectionInformation connectionInformation,
final HmilySQLComputeEngine sqlComputeEngine, final String resourceId) {
LockRetryController lockRetryController = new LockRetryController();
while (true) {
try {
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
log.debug("TAC-compute-sql ::: {}", snapshot);
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
// check the global lock
HmilyLockManager.INSTANCE.checkLocks(undoContext.getHmilyLocks());
log.debug("TAC-check-lock ::: {}", undoContext.getHmilyLocks());
break;
} catch (HmilyLockConflictException hlce) {
// trigger retry
lockRetryController.sleep(hlce);
}
}
final HmilySQLComputeEngine sqlComputeEngine, final String resourceId, final int lockRetryInterval, final int lockRetryTimes) {
new HmilyLockRetryPolicy(lockRetryInterval, lockRetryTimes).execute(() -> {
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
log.debug("TAC-compute-sql ::: {}", snapshot);
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
// check the global lock
HmilyLockManager.INSTANCE.checkLocks(undoContext.getHmilyLocks());
log.debug("TAC-check-lock ::: {}", undoContext.getHmilyLocks());
});
}

private HmilyUndoContext buildUndoContext(final HmilyTransactionContext transactionContext, final HmilyDataSnapshot dataSnapshot, final String resourceId) {
Expand Down Expand Up @@ -208,4 +208,35 @@ private boolean check() {
HmilyTransactionContext transactionContext = HmilyContextHolder.get();
return Objects.isNull(transactionContext) || !TransTypeEnum.TAC.name().equalsIgnoreCase(transactionContext.getTransType());
}

private static class HmilyLockRetryPolicy {
protected static final boolean LOCK_RETRY_POLICY = ConfigEnv.getInstance().getConfig(HmilyConfig.class).isLockRetryPolicy();

private final HmilyLockRetryHandler hmilyLockRetryHandler;

HmilyLockRetryPolicy(final int lockRetryInterval, final int lockRetryTimes) {
this.hmilyLockRetryHandler = new HmilyLockRetryHandler(lockRetryInterval, lockRetryTimes);
}

private void execute(final Runnable task) {
if (!LOCK_RETRY_POLICY) {
task.run();
} else {
doRetryOnLockConflict(task);
}
}

private void doRetryOnLockConflict(final Runnable task) {
while (true) {
try {
// execute the task that need to be retried
task.run();
break;
} catch (HmilyLockConflictException hlce) {
// trigger retry
hmilyLockRetryHandler.sleep(hlce);
}
}
}
}
}

0 comments on commit 52dc6ba

Please sign in to comment.