Skip to content

Commit 91c3c25

Browse files
SweetWuXiaoMeisebersole
authored andcommitted
HHH-19682 - Add Support for GaussDB Lock Timeout (lockwait_timeout)
1 parent 5acb4fe commit 91c3c25

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/lock/internal/GaussDBLockingSupport.java

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@
44
*/
55
package org.hibernate.community.dialect.lock.internal;
66

7+
import jakarta.persistence.Timeout;
8+
import org.hibernate.HibernateException;
9+
import org.hibernate.Timeouts;
710
import org.hibernate.dialect.RowLockStrategy;
11+
import org.hibernate.dialect.lock.internal.Helper;
812
import org.hibernate.dialect.lock.spi.ConnectionLockTimeoutStrategy;
13+
import org.hibernate.dialect.lock.spi.LockTimeoutType;
914
import org.hibernate.dialect.lock.spi.LockingSupport;
1015
import org.hibernate.dialect.lock.spi.OuterJoinLockingType;
16+
import org.hibernate.engine.spi.SessionFactoryImplementor;
1117

18+
import java.sql.Connection;
19+
20+
import static org.hibernate.Timeouts.NO_WAIT_MILLI;
21+
import static org.hibernate.Timeouts.SKIP_LOCKED_MILLI;
22+
import static org.hibernate.Timeouts.WAIT_FOREVER_MILLI;
23+
import static org.hibernate.dialect.lock.spi.LockTimeoutType.QUERY;
1224

1325

1426
/**
@@ -18,7 +30,17 @@
1830
*/
1931
public class GaussDBLockingSupport implements LockingSupport, LockingSupport.Metadata, ConnectionLockTimeoutStrategy {
2032
public static final LockingSupport LOCKING_SUPPORT = new GaussDBLockingSupport();
33+
private final boolean supportsNoWait;
34+
private final boolean supportsSkipLocked;
35+
36+
public GaussDBLockingSupport() {
37+
this( true, true );
38+
}
2139

40+
public GaussDBLockingSupport(boolean supportsNoWait, boolean supportsSkipLocked) {
41+
this.supportsNoWait = supportsNoWait;
42+
this.supportsSkipLocked = supportsSkipLocked;
43+
}
2244

2345
@Override
2446
public Metadata getMetadata() {
@@ -42,6 +64,71 @@ public ConnectionLockTimeoutStrategy getConnectionLockTimeoutStrategy() {
4264

4365
@Override
4466
public Level getSupportedLevel() {
45-
return Level.NONE;
67+
return Level.SUPPORTED;
68+
}
69+
70+
@Override
71+
public LockTimeoutType getLockTimeoutType(Timeout timeout) {
72+
return switch ( timeout.milliseconds() ) {
73+
case NO_WAIT_MILLI -> supportsNoWait ? QUERY : LockTimeoutType.NONE;
74+
case SKIP_LOCKED_MILLI -> supportsSkipLocked ? QUERY : LockTimeoutType.NONE;
75+
case WAIT_FOREVER_MILLI -> LockTimeoutType.NONE;
76+
// we can apply a timeout via the connection
77+
default -> LockTimeoutType.CONNECTION;
78+
};
79+
}
80+
81+
@Override
82+
public Timeout getLockTimeout(Connection connection, SessionFactoryImplementor factory) {
83+
return Helper.getLockTimeout(
84+
"select current_setting('lockwait_timeout')",
85+
(resultSet) -> {
86+
// even though lock_timeout is "in milliseconds", `current_setting`
87+
// returns a String form which unfortunately varies depending on
88+
// the actual value:
89+
// * for zero (no timeout), "0" is returned
90+
// * for non-zero, `{timeout-in-seconds}s` is returned (e.g. "4s")
91+
// so we need to "parse" that form here
92+
final String value = resultSet.getString( 1 );
93+
if ( "0".equals( value ) ) {
94+
return Timeouts.WAIT_FOREVER;
95+
}
96+
if ( value.endsWith( "min" ) ) {
97+
final int min = Integer.parseInt( value.substring( 0, value.length() - 3 ) );
98+
return Timeout.milliseconds( min * 60 * 1000 );
99+
}
100+
else if ( value.endsWith( "s" ) ) {
101+
final int second = Integer.parseInt( value.substring( 0, value.length() - 1 ) );
102+
return Timeout.seconds(second);
103+
}
104+
final int milliseconds = Integer.parseInt( value.substring( 0, value.length() - 2 ) );
105+
return Timeout.milliseconds(milliseconds);
106+
},
107+
connection,
108+
factory
109+
);
110+
}
111+
112+
@Override
113+
public void setLockTimeout(Timeout timeout, Connection connection, SessionFactoryImplementor factory) {
114+
Helper.setLockTimeout(
115+
timeout,
116+
(t) -> {
117+
final int milliseconds = timeout.milliseconds();
118+
if ( milliseconds == SKIP_LOCKED_MILLI ) {
119+
throw new HibernateException( "Connection lock-timeout does not accept skip-locked" );
120+
}
121+
122+
if ( milliseconds == NO_WAIT_MILLI ) {
123+
throw new HibernateException( "Connection lock-timeout does not accept no-wait" );
124+
}
125+
return milliseconds == WAIT_FOREVER_MILLI
126+
? 0
127+
: milliseconds;
128+
},
129+
"set local lockwait_timeout = %s",
130+
connection,
131+
factory
132+
);
46133
}
47134
}

hibernate-core/src/test/java/org/hibernate/orm/test/locking/options/ConnectionLockTimeoutTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import jakarta.persistence.Timeout;
88
import org.hibernate.Timeouts;
9+
import org.hibernate.community.dialect.GaussDBDialect;
910
import org.hibernate.dialect.MySQLDialect;
1011
import org.hibernate.dialect.lock.spi.ConnectionLockTimeoutStrategy;
1112
import org.hibernate.dialect.lock.spi.LockingSupport;
@@ -35,6 +36,9 @@ void testSimpleUsage(SessionFactoryScope factoryScope) {
3536
if ( session.getDialect() instanceof MySQLDialect ) {
3637
expectedInitialValue = 50;
3738
}
39+
else if ( session.getDialect() instanceof GaussDBDialect ) {
40+
expectedInitialValue = 20 * 60 * 1000;
41+
}
3842
else {
3943
expectedInitialValue = Timeouts.WAIT_FOREVER_MILLI;
4044
}

0 commit comments

Comments
 (0)