Skip to content

Commit 334af03

Browse files
zkyomazhaojun@middleware
authored andcommitted
Customized global lock retry interval and lock retry times and optimize lock retry mechanism. (#370)
1 parent 6a67102 commit 334af03

File tree

6 files changed

+91
-30
lines changed

6 files changed

+91
-30
lines changed

hmily-annotation/src/main/java/org/dromara/hmily/annotation/HmilyTAC.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,18 @@
3636
* @return the transaction isolation level enum
3737
*/
3838
IsolationLevelEnum isolationLevel() default IsolationLevelEnum.READ_UNCOMMITTED;
39+
40+
/**
41+
* customized global lock retry interval(unit: ms).
42+
*
43+
* @return lock retry interval
44+
*/
45+
int lockRetryInterval() default 0;
46+
47+
/**
48+
* customized global lock retry times.
49+
*
50+
* @return lock retry times
51+
*/
52+
int lockRetryTimes() default -1;
3953
}

hmily-config/hmily-config-api/src/main/java/org/dromara/hmily/config/api/entity/HmilyConfig.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ public class HmilyConfig extends AbstractConfig {
148148
* global lock retry times.
149149
*/
150150
private int lockRetryTimes = 30;
151+
152+
/**
153+
* whether the lock retry policy is enabled.
154+
*/
155+
private boolean lockRetryPolicy = true;
151156

152157
@Override
153158
public String prefix() {

hmily-core/src/main/java/org/dromara/hmily/core/context/HmilyTransactionContext.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ public class HmilyTransactionContext {
6464
*/
6565
private int isolationLevel;
6666

67+
/**
68+
* lock retry interval.
69+
*/
70+
private int lockRetryInterval;
71+
72+
/**
73+
* lock retry times.
74+
*/
75+
private int lockRetryTimes;
76+
6777
//以下为xa相关的参数.
6878
/**
6979
* xa相关的参数定义.
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @author zhangzhi
1212
*/
1313
@Slf4j
14-
public class LockRetryController {
14+
public class HmilyLockRetryHandler {
1515

1616
private int lockRetryInterval;
1717

@@ -20,10 +20,10 @@ public class LockRetryController {
2020
/**
2121
* Instantiates a new Lock retry controller.
2222
*/
23-
public LockRetryController() {
23+
public HmilyLockRetryHandler(final int lockRetryInterval, final int lockRetryTimes) {
2424
HmilyConfig hmilyConfig = ConfigEnv.getInstance().getConfig(HmilyConfig.class);
25-
this.lockRetryInterval = hmilyConfig.getLockRetryInterval();
26-
this.lockRetryTimes = hmilyConfig.getLockRetryTimes();
25+
this.lockRetryInterval = lockRetryInterval <= 0 ? hmilyConfig.getLockRetryInterval() : lockRetryInterval;
26+
this.lockRetryTimes = lockRetryTimes < 0 ? hmilyConfig.getLockRetryTimes() : lockRetryTimes;
2727
}
2828

2929
/**
@@ -32,7 +32,6 @@ public LockRetryController() {
3232
* @throws LockWaitTimeoutException the lock wait timeout exception
3333
*/
3434
public void sleep(final Exception e) {
35-
// prioritize the rollback of other transactions
3635
if (--lockRetryTimes < 0) {
3736
log.error("Global lock wait timeout");
3837
throw new LockWaitTimeoutException("Global lock wait timeout", e);

hmily-tac/hmily-tac-core/src/main/java/org/dromara/hmily/tac/core/transaction/HmilyTacTransactionManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public HmilyTransaction begin(final ProceedingJoinPoint point) {
8585
Method method = signature.getMethod();
8686
final HmilyTAC hmilyTAC = method.getAnnotation(HmilyTAC.class);
8787
context.setIsolationLevel(hmilyTAC.isolationLevel().getValue());
88+
context.setLockRetryInterval(hmilyTAC.lockRetryInterval());
89+
context.setLockRetryTimes(hmilyTAC.lockRetryTimes());
8890
context.setParticipantId(hmilyParticipant.getParticipantId());
8991
HmilyContextHolder.set(context);
9092
log.debug("TAC-tm-begin ::: {}", globalHmilyTransaction);

hmily-tac/hmily-tac-p6spy/src/main/java/org/dromara/hmily/tac/p6spy/executor/HmilyExecuteTemplate.java

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.dromara.hmily.annotation.TransTypeEnum;
2424
import org.dromara.hmily.common.enums.HmilyActionEnum;
2525
import org.dromara.hmily.common.utils.IdWorkerUtils;
26+
import org.dromara.hmily.config.api.ConfigEnv;
27+
import org.dromara.hmily.config.api.entity.HmilyConfig;
2628
import org.dromara.hmily.core.context.HmilyContextHolder;
2729
import org.dromara.hmily.core.context.HmilyTransactionContext;
2830
import org.dromara.hmily.core.repository.HmilyRepositoryStorage;
@@ -36,7 +38,7 @@
3638
import org.dromara.hmily.tac.core.cache.HmilyUndoContextCacheManager;
3739
import org.dromara.hmily.tac.core.context.HmilyUndoContext;
3840
import org.dromara.hmily.tac.core.lock.HmilyLockManager;
39-
import org.dromara.hmily.tac.core.lock.LockRetryController;
41+
import org.dromara.hmily.tac.core.lock.HmilyLockRetryHandler;
4042
import org.dromara.hmily.tac.p6spy.threadlocal.AutoCommitThreadLocal;
4143
import org.dromara.hmily.tac.sqlcompute.HmilySQLComputeEngine;
4244
import org.dromara.hmily.tac.sqlcompute.HmilySQLComputeEngineFactory;
@@ -102,40 +104,38 @@ public void execute(final String sql, final List<Object> parameters, final Conne
102104
}
103105
String resourceId = ResourceIdUtils.INSTANCE.getResourceId(connectionInformation.getUrl());
104106
HmilySQLComputeEngine sqlComputeEngine = HmilySQLComputeEngineFactory.newInstance(statement);
105-
// select SQL
106107
HmilyTransactionContext transactionContext = HmilyContextHolder.get();
108+
int lockRetryInterval = transactionContext.getLockRetryInterval();
109+
int lockRetryTimes = transactionContext.getLockRetryTimes();
110+
// select SQL
107111
if (statement instanceof HmilySelectStatement) {
108112
if (IsolationLevelEnum.READ_COMMITTED.getValue() == transactionContext.getIsolationLevel()) {
109113
// read committed level need check locks
110-
executeSelect(sql, parameters, connectionInformation, sqlComputeEngine, resourceId);
114+
executeSelect(sql, parameters, connectionInformation, sqlComputeEngine, resourceId, lockRetryInterval, lockRetryTimes);
111115
}
112116
return;
113117
}
114-
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
115-
log.debug("TAC-compute-sql ::: {}", snapshot);
116-
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
117-
HmilyLockManager.INSTANCE.tryAcquireLocks(undoContext.getHmilyLocks());
118-
log.debug("TAC-try-lock ::: {}", undoContext.getHmilyLocks());
119-
HmilyUndoContextCacheManager.INSTANCE.set(undoContext);
118+
// update delete insert SQL
119+
new HmilyLockRetryPolicy(lockRetryInterval, lockRetryTimes).execute(() -> {
120+
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
121+
log.debug("TAC-compute-sql ::: {}", snapshot);
122+
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
123+
HmilyLockManager.INSTANCE.tryAcquireLocks(undoContext.getHmilyLocks());
124+
log.debug("TAC-try-lock ::: {}", undoContext.getHmilyLocks());
125+
HmilyUndoContextCacheManager.INSTANCE.set(undoContext);
126+
});
120127
}
121128

122129
private void executeSelect(final String sql, final List<Object> parameters, final ConnectionInformation connectionInformation,
123-
final HmilySQLComputeEngine sqlComputeEngine, final String resourceId) {
124-
LockRetryController lockRetryController = new LockRetryController();
125-
while (true) {
126-
try {
127-
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
128-
log.debug("TAC-compute-sql ::: {}", snapshot);
129-
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
130-
// check the global lock
131-
HmilyLockManager.INSTANCE.checkLocks(undoContext.getHmilyLocks());
132-
log.debug("TAC-check-lock ::: {}", undoContext.getHmilyLocks());
133-
break;
134-
} catch (HmilyLockConflictException hlce) {
135-
// trigger retry
136-
lockRetryController.sleep(hlce);
137-
}
138-
}
130+
final HmilySQLComputeEngine sqlComputeEngine, final String resourceId, final int lockRetryInterval, final int lockRetryTimes) {
131+
new HmilyLockRetryPolicy(lockRetryInterval, lockRetryTimes).execute(() -> {
132+
HmilyDataSnapshot snapshot = sqlComputeEngine.execute(sql, parameters, connectionInformation.getConnection(), resourceId);
133+
log.debug("TAC-compute-sql ::: {}", snapshot);
134+
HmilyUndoContext undoContext = buildUndoContext(HmilyContextHolder.get(), snapshot, resourceId);
135+
// check the global lock
136+
HmilyLockManager.INSTANCE.checkLocks(undoContext.getHmilyLocks());
137+
log.debug("TAC-check-lock ::: {}", undoContext.getHmilyLocks());
138+
});
139139
}
140140

141141
private HmilyUndoContext buildUndoContext(final HmilyTransactionContext transactionContext, final HmilyDataSnapshot dataSnapshot, final String resourceId) {
@@ -208,4 +208,35 @@ private boolean check() {
208208
HmilyTransactionContext transactionContext = HmilyContextHolder.get();
209209
return Objects.isNull(transactionContext) || !TransTypeEnum.TAC.name().equalsIgnoreCase(transactionContext.getTransType());
210210
}
211+
212+
private static class HmilyLockRetryPolicy {
213+
protected static final boolean LOCK_RETRY_POLICY = ConfigEnv.getInstance().getConfig(HmilyConfig.class).isLockRetryPolicy();
214+
215+
private final HmilyLockRetryHandler hmilyLockRetryHandler;
216+
217+
HmilyLockRetryPolicy(final int lockRetryInterval, final int lockRetryTimes) {
218+
this.hmilyLockRetryHandler = new HmilyLockRetryHandler(lockRetryInterval, lockRetryTimes);
219+
}
220+
221+
private void execute(final Runnable task) {
222+
if (!LOCK_RETRY_POLICY) {
223+
task.run();
224+
} else {
225+
doRetryOnLockConflict(task);
226+
}
227+
}
228+
229+
private void doRetryOnLockConflict(final Runnable task) {
230+
while (true) {
231+
try {
232+
// execute the task that need to be retried
233+
task.run();
234+
break;
235+
} catch (HmilyLockConflictException hlce) {
236+
// trigger retry
237+
hmilyLockRetryHandler.sleep(hlce);
238+
}
239+
}
240+
}
241+
}
211242
}

0 commit comments

Comments
 (0)