mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-13 05:59:01 +08:00
✨ Introducing new features. 内置 seata-server 模块 方便调试
This commit is contained in:
1 parent
1c4f447355
commit
1967b1d443
576 files changed
+11957
-79957
No files matched your search
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.BranchTransactionException;
|
||||
import io.seata.core.exception.GlobalTransactionException;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.exception.TransactionExceptionCode;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.server.store.SessionStorable;
|
||||
import io.seata.server.store.TransactionStoreManager;
|
||||
import io.seata.server.store.TransactionStoreManager.LogOperation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The type Abstract session manager.
|
||||
*/
|
||||
public abstract class AbstractSessionManager implements SessionManager, SessionLifecycleListener {
|
||||
|
||||
/**
|
||||
* The constant LOGGER.
|
||||
*/
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractSessionManager.class);
|
||||
|
||||
/**
|
||||
* The Transaction store manager.
|
||||
*/
|
||||
protected TransactionStoreManager transactionStoreManager;
|
||||
|
||||
/**
|
||||
* The Name.
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract session manager.
|
||||
*/
|
||||
public AbstractSessionManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract session manager.
|
||||
* @param name the name
|
||||
*/
|
||||
public AbstractSessionManager(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGlobalSession(GlobalSession session) throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + session + "] " + LogOperation.GLOBAL_ADD);
|
||||
}
|
||||
writeSession(LogOperation.GLOBAL_ADD, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + session + "] " + LogOperation.GLOBAL_UPDATE);
|
||||
}
|
||||
writeSession(LogOperation.GLOBAL_UPDATE, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGlobalSession(GlobalSession session) throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + session + "] " + LogOperation.GLOBAL_REMOVE);
|
||||
}
|
||||
writeSession(LogOperation.GLOBAL_REMOVE, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBranchSession(GlobalSession session, BranchSession branchSession) throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + branchSession + "] " + LogOperation.BRANCH_ADD);
|
||||
}
|
||||
writeSession(LogOperation.BRANCH_ADD, branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBranchSessionStatus(BranchSession branchSession, BranchStatus status)
|
||||
throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + branchSession + "] " + LogOperation.BRANCH_UPDATE);
|
||||
}
|
||||
writeSession(LogOperation.BRANCH_UPDATE, branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBranchSession(GlobalSession globalSession, BranchSession branchSession)
|
||||
throws TransactionException {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("MANAGER[" + name + "] SESSION[" + branchSession + "] " + LogOperation.BRANCH_REMOVE);
|
||||
}
|
||||
writeSession(LogOperation.BRANCH_REMOVE, branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBegin(GlobalSession globalSession) throws TransactionException {
|
||||
addGlobalSession(globalSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChange(GlobalSession globalSession, GlobalStatus status) throws TransactionException {
|
||||
updateGlobalSessionStatus(globalSession, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBranchStatusChange(GlobalSession globalSession, BranchSession branchSession, BranchStatus status)
|
||||
throws TransactionException {
|
||||
updateBranchSessionStatus(branchSession, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException {
|
||||
addBranchSession(globalSession, branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoveBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException {
|
||||
removeBranchSession(globalSession, branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(GlobalSession globalSession) throws TransactionException {
|
||||
globalSession.setActive(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(GlobalSession globalSession) throws TransactionException {
|
||||
removeGlobalSession(globalSession);
|
||||
}
|
||||
|
||||
private void writeSession(LogOperation logOperation, SessionStorable sessionStorable) throws TransactionException {
|
||||
if (!transactionStoreManager.writeSession(logOperation, sessionStorable)) {
|
||||
if (LogOperation.GLOBAL_ADD.equals(logOperation)) {
|
||||
throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to store global session");
|
||||
}
|
||||
else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) {
|
||||
throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to update global session");
|
||||
}
|
||||
else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) {
|
||||
throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to remove global session");
|
||||
}
|
||||
else if (LogOperation.BRANCH_ADD.equals(logOperation)) {
|
||||
throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to store branch session");
|
||||
}
|
||||
else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) {
|
||||
throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to update branch session");
|
||||
}
|
||||
else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) {
|
||||
throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Fail to remove branch session");
|
||||
}
|
||||
else {
|
||||
throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession,
|
||||
"Unknown LogOperation:" + logOperation.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets transaction store manager.
|
||||
* @param transactionStoreManager the transaction store manager
|
||||
*/
|
||||
public void setTransactionStoreManager(TransactionStoreManager transactionStoreManager) {
|
||||
this.transactionStoreManager = transactionStoreManager;
|
||||
}
|
||||
|
||||
}
|
||||
+436
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import io.seata.server.storage.file.lock.FileLocker;
|
||||
import io.seata.common.util.CompressUtil;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.BranchType;
|
||||
import io.seata.server.lock.LockerManagerFactory;
|
||||
import io.seata.server.store.SessionStorable;
|
||||
import io.seata.server.store.StoreConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The type Branch session.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public class BranchSession implements Lockable, Comparable<BranchSession>, SessionStorable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BranchSession.class);
|
||||
|
||||
private static final int MAX_BRANCH_SESSION_SIZE = StoreConfig.getMaxBranchSessionSize();
|
||||
|
||||
private static ThreadLocal<ByteBuffer> byteBufferThreadLocal = ThreadLocal
|
||||
.withInitial(() -> ByteBuffer.allocate(MAX_BRANCH_SESSION_SIZE));
|
||||
|
||||
private String xid;
|
||||
|
||||
private long transactionId;
|
||||
|
||||
private long branchId;
|
||||
|
||||
private String resourceGroupId;
|
||||
|
||||
private String resourceId;
|
||||
|
||||
private String lockKey;
|
||||
|
||||
private BranchType branchType;
|
||||
|
||||
private BranchStatus status = BranchStatus.Unknown;
|
||||
|
||||
private String clientId;
|
||||
|
||||
private String applicationData;
|
||||
|
||||
private ConcurrentMap<FileLocker.BucketLockMap, Set<String>> lockHolder = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Gets application data.
|
||||
* @return the application data
|
||||
*/
|
||||
public String getApplicationData() {
|
||||
return applicationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets application data.
|
||||
* @param applicationData the application data
|
||||
*/
|
||||
public void setApplicationData(String applicationData) {
|
||||
this.applicationData = applicationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets resource group id.
|
||||
* @return the resource group id
|
||||
*/
|
||||
public String getResourceGroupId() {
|
||||
return resourceGroupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource group id.
|
||||
* @param resourceGroupId the resource group id
|
||||
*/
|
||||
public void setResourceGroupId(String resourceGroupId) {
|
||||
this.resourceGroupId = resourceGroupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets client id.
|
||||
* @return the client id
|
||||
*/
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets client id.
|
||||
* @param clientId the client id
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets resource id.
|
||||
* @return the resource id
|
||||
*/
|
||||
public String getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource id.
|
||||
* @param resourceId the resource id
|
||||
*/
|
||||
public void setResourceId(String resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets lock key.
|
||||
* @return the lock key
|
||||
*/
|
||||
public String getLockKey() {
|
||||
return lockKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets lock key.
|
||||
* @param lockKey the lock key
|
||||
*/
|
||||
public void setLockKey(String lockKey) {
|
||||
this.lockKey = lockKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets branch type.
|
||||
* @return the branch type
|
||||
*/
|
||||
public BranchType getBranchType() {
|
||||
return branchType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets branch type.
|
||||
* @param branchType the branch type
|
||||
*/
|
||||
public void setBranchType(BranchType branchType) {
|
||||
this.branchType = branchType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets status.
|
||||
* @return the status
|
||||
*/
|
||||
public BranchStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets status.
|
||||
* @param status the status
|
||||
*/
|
||||
public void setStatus(BranchStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets transaction id.
|
||||
* @return the transaction id
|
||||
*/
|
||||
public long getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets transaction id.
|
||||
* @param transactionId the transaction id
|
||||
*/
|
||||
public void setTransactionId(long transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets branch id.
|
||||
* @return the branch id
|
||||
*/
|
||||
public long getBranchId() {
|
||||
return branchId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets branch id.
|
||||
* @param branchId the branch id
|
||||
*/
|
||||
public void setBranchId(long branchId) {
|
||||
this.branchId = branchId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets xid.
|
||||
* @return the xid
|
||||
*/
|
||||
public String getXid() {
|
||||
return xid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets xid.
|
||||
* @param xid the xid
|
||||
*/
|
||||
public void setXid(String xid) {
|
||||
this.xid = xid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BR:" + branchId + "/" + transactionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BranchSession o) {
|
||||
return Long.compare(this.branchId, o.branchId);
|
||||
}
|
||||
|
||||
public boolean canBeCommittedAsync() {
|
||||
return branchType == BranchType.AT || status == BranchStatus.PhaseOne_Failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets lock holder.
|
||||
* @return the lock holder
|
||||
*/
|
||||
public ConcurrentMap<FileLocker.BucketLockMap, Set<String>> getLockHolder() {
|
||||
return lockHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lock() throws TransactionException {
|
||||
if (this.getBranchType().equals(BranchType.AT)) {
|
||||
return LockerManagerFactory.getLockManager().acquireLock(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlock() throws TransactionException {
|
||||
if (this.getBranchType() == BranchType.AT) {
|
||||
return LockerManagerFactory.getLockManager().releaseLock(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
|
||||
byte[] resourceIdBytes = resourceId != null ? resourceId.getBytes() : null;
|
||||
|
||||
byte[] lockKeyBytes = lockKey != null ? lockKey.getBytes() : null;
|
||||
|
||||
byte[] clientIdBytes = clientId != null ? clientId.getBytes() : null;
|
||||
|
||||
byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes() : null;
|
||||
|
||||
byte[] xidBytes = xid != null ? xid.getBytes() : null;
|
||||
|
||||
byte branchTypeByte = branchType != null ? (byte) branchType.ordinal() : -1;
|
||||
|
||||
int size = calBranchSessionSize(resourceIdBytes, lockKeyBytes, clientIdBytes, applicationDataBytes, xidBytes);
|
||||
|
||||
if (size > MAX_BRANCH_SESSION_SIZE) {
|
||||
if (lockKeyBytes == null) {
|
||||
throw new RuntimeException("branch session size exceeded, size : " + size + " maxBranchSessionSize : "
|
||||
+ MAX_BRANCH_SESSION_SIZE);
|
||||
}
|
||||
// try compress lockkey
|
||||
try {
|
||||
size -= lockKeyBytes.length;
|
||||
lockKeyBytes = CompressUtil.compress(lockKeyBytes);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOGGER.error("compress lockKey error", e);
|
||||
}
|
||||
finally {
|
||||
size += lockKeyBytes.length;
|
||||
}
|
||||
|
||||
if (size > MAX_BRANCH_SESSION_SIZE) {
|
||||
throw new RuntimeException("compress branch session size exceeded, compressSize : " + size
|
||||
+ " maxBranchSessionSize : " + MAX_BRANCH_SESSION_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer byteBuffer = byteBufferThreadLocal.get();
|
||||
// recycle
|
||||
byteBuffer.clear();
|
||||
|
||||
byteBuffer.putLong(transactionId);
|
||||
byteBuffer.putLong(branchId);
|
||||
|
||||
if (resourceIdBytes != null) {
|
||||
byteBuffer.putInt(resourceIdBytes.length);
|
||||
byteBuffer.put(resourceIdBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
|
||||
if (lockKeyBytes != null) {
|
||||
byteBuffer.putInt(lockKeyBytes.length);
|
||||
byteBuffer.put(lockKeyBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
|
||||
if (clientIdBytes != null) {
|
||||
byteBuffer.putShort((short) clientIdBytes.length);
|
||||
byteBuffer.put(clientIdBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putShort((short) 0);
|
||||
}
|
||||
|
||||
if (applicationDataBytes != null) {
|
||||
byteBuffer.putInt(applicationDataBytes.length);
|
||||
byteBuffer.put(applicationDataBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
|
||||
if (xidBytes != null) {
|
||||
byteBuffer.putInt(xidBytes.length);
|
||||
byteBuffer.put(xidBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
|
||||
byteBuffer.put(branchTypeByte);
|
||||
|
||||
byteBuffer.put((byte) status.getCode());
|
||||
byteBuffer.flip();
|
||||
byte[] result = new byte[byteBuffer.limit()];
|
||||
byteBuffer.get(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private int calBranchSessionSize(byte[] resourceIdBytes, byte[] lockKeyBytes, byte[] clientIdBytes,
|
||||
byte[] applicationDataBytes, byte[] xidBytes) {
|
||||
final int size = 8 // trascationId
|
||||
+ 8 // branchId
|
||||
+ 4 // resourceIdBytes.length
|
||||
+ 4 // lockKeyBytes.length
|
||||
+ 2 // clientIdBytes.length
|
||||
+ 4 // applicationDataBytes.length
|
||||
+ 4 // xidBytes.size
|
||||
+ 1 // statusCode
|
||||
+ (resourceIdBytes == null ? 0 : resourceIdBytes.length)
|
||||
+ (lockKeyBytes == null ? 0 : lockKeyBytes.length) + (clientIdBytes == null ? 0 : clientIdBytes.length)
|
||||
+ (applicationDataBytes == null ? 0 : applicationDataBytes.length)
|
||||
+ (xidBytes == null ? 0 : xidBytes.length) + 1; // branchType
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(byte[] a) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(a);
|
||||
this.transactionId = byteBuffer.getLong();
|
||||
this.branchId = byteBuffer.getLong();
|
||||
int resourceLen = byteBuffer.getInt();
|
||||
if (resourceLen > 0) {
|
||||
byte[] byResource = new byte[resourceLen];
|
||||
byteBuffer.get(byResource);
|
||||
this.resourceId = new String(byResource);
|
||||
}
|
||||
int lockKeyLen = byteBuffer.getInt();
|
||||
if (lockKeyLen > 0) {
|
||||
byte[] byLockKey = new byte[lockKeyLen];
|
||||
byteBuffer.get(byLockKey);
|
||||
if (CompressUtil.isCompressData(byLockKey)) {
|
||||
try {
|
||||
this.lockKey = new String(CompressUtil.uncompress(byLockKey));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("decompress lockKey error", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.lockKey = new String(byLockKey);
|
||||
}
|
||||
|
||||
}
|
||||
short clientIdLen = byteBuffer.getShort();
|
||||
if (clientIdLen > 0) {
|
||||
byte[] byClientId = new byte[clientIdLen];
|
||||
byteBuffer.get(byClientId);
|
||||
this.clientId = new String(byClientId);
|
||||
}
|
||||
int applicationDataLen = byteBuffer.getInt();
|
||||
if (applicationDataLen > 0) {
|
||||
byte[] byApplicationData = new byte[applicationDataLen];
|
||||
byteBuffer.get(byApplicationData);
|
||||
this.applicationData = new String(byApplicationData);
|
||||
}
|
||||
int xidLen = byteBuffer.getInt();
|
||||
if (xidLen > 0) {
|
||||
byte[] xidBytes = new byte[xidLen];
|
||||
byteBuffer.get(xidBytes);
|
||||
this.xid = new String(xidBytes);
|
||||
}
|
||||
int branchTypeId = byteBuffer.get();
|
||||
if (branchTypeId >= 0) {
|
||||
this.branchType = BranchType.values()[branchTypeId];
|
||||
}
|
||||
this.status = BranchStatus.get(byteBuffer.get());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.TransactionException;
|
||||
|
||||
/**
|
||||
* The Functional Interface Branch session handler
|
||||
*
|
||||
* @author wang.liang
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BranchSessionHandler {
|
||||
|
||||
Boolean CONTINUE = null;
|
||||
|
||||
/**
|
||||
* Handle branch session.
|
||||
* @param branchSession the branch session
|
||||
* @return the handle result
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
Boolean handle(BranchSession branchSession) throws TransactionException;
|
||||
|
||||
}
|
||||
+684
@@ -0,0 +1,684 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import io.seata.common.Constants;
|
||||
import io.seata.common.DefaultValues;
|
||||
import io.seata.common.XID;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import io.seata.config.ConfigurationFactory;
|
||||
import io.seata.core.constants.ConfigurationKeys;
|
||||
import io.seata.core.exception.GlobalTransactionException;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.exception.TransactionExceptionCode;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.BranchType;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.server.UUIDGenerator;
|
||||
import io.seata.server.lock.LockerManagerFactory;
|
||||
import io.seata.server.store.SessionStorable;
|
||||
import io.seata.server.store.StoreConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.seata.core.model.GlobalStatus.AsyncCommitting;
|
||||
import static io.seata.core.model.GlobalStatus.CommitRetrying;
|
||||
import static io.seata.core.model.GlobalStatus.Committing;
|
||||
|
||||
/**
|
||||
* The type Global session.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public class GlobalSession implements SessionLifecycle, SessionStorable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalSession.class);
|
||||
|
||||
private static final int MAX_GLOBAL_SESSION_SIZE = StoreConfig.getMaxGlobalSessionSize();
|
||||
|
||||
private static ThreadLocal<ByteBuffer> byteBufferThreadLocal = ThreadLocal
|
||||
.withInitial(() -> ByteBuffer.allocate(MAX_GLOBAL_SESSION_SIZE));
|
||||
|
||||
/**
|
||||
* If the global session's status is (Rollbacking or Committing) and currentTime -
|
||||
* createTime >= RETRY_DEAD_THRESHOLD then the tx will be remand as need to retry
|
||||
* rollback
|
||||
*/
|
||||
private static final int RETRY_DEAD_THRESHOLD = ConfigurationFactory.getInstance()
|
||||
.getInt(ConfigurationKeys.RETRY_DEAD_THRESHOLD, DefaultValues.DEFAULT_RETRY_DEAD_THRESHOLD);
|
||||
|
||||
private String xid;
|
||||
|
||||
private long transactionId;
|
||||
|
||||
private volatile GlobalStatus status;
|
||||
|
||||
private String applicationId;
|
||||
|
||||
private String transactionServiceGroup;
|
||||
|
||||
private String transactionName;
|
||||
|
||||
private int timeout;
|
||||
|
||||
private long beginTime;
|
||||
|
||||
private String applicationData;
|
||||
|
||||
private volatile boolean active = true;
|
||||
|
||||
private final ArrayList<BranchSession> branchSessions = new ArrayList<>();
|
||||
|
||||
private GlobalSessionLock globalSessionLock = new GlobalSessionLock();
|
||||
|
||||
/**
|
||||
* Add boolean.
|
||||
* @param branchSession the branch session
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean add(BranchSession branchSession) {
|
||||
return branchSessions.add(branchSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove boolean.
|
||||
* @param branchSession the branch session
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean remove(BranchSession branchSession) {
|
||||
return branchSessions.remove(branchSession);
|
||||
}
|
||||
|
||||
private Set<SessionLifecycleListener> lifecycleListeners = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Can be committed async boolean.
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean canBeCommittedAsync() {
|
||||
for (BranchSession branchSession : branchSessions) {
|
||||
if (!branchSession.canBeCommittedAsync()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has AT branch
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean hasATBranch() {
|
||||
for (BranchSession branchSession : branchSessions) {
|
||||
if (branchSession.getBranchType() == BranchType.AT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is saga type transaction
|
||||
* @return is saga
|
||||
*/
|
||||
public boolean isSaga() {
|
||||
if (branchSessions.size() > 0) {
|
||||
return BranchType.SAGA == branchSessions.get(0).getBranchType();
|
||||
}
|
||||
else {
|
||||
return StringUtils.isNotBlank(transactionName)
|
||||
&& transactionName.startsWith(Constants.SAGA_TRANS_NAME_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is timeout boolean.
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean isTimeout() {
|
||||
return (System.currentTimeMillis() - beginTime) > timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* prevent could not handle committing and rollbacking transaction
|
||||
* @return if true retry commit or roll back
|
||||
*/
|
||||
public boolean isDeadSession() {
|
||||
return (System.currentTimeMillis() - beginTime) > RETRY_DEAD_THRESHOLD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void begin() throws TransactionException {
|
||||
this.status = GlobalStatus.Begin;
|
||||
this.beginTime = System.currentTimeMillis();
|
||||
this.active = true;
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onBegin(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeStatus(GlobalStatus status) throws TransactionException {
|
||||
this.status = status;
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onStatusChange(this, status);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeBranchStatus(BranchSession branchSession, BranchStatus status) throws TransactionException {
|
||||
branchSession.setStatus(status);
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onBranchStatusChange(this, branchSession, status);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws TransactionException {
|
||||
if (active) {
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onClose(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() throws TransactionException {
|
||||
// Clean locks first
|
||||
clean();
|
||||
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onEnd(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void clean() throws TransactionException {
|
||||
if (this.hasATBranch()) {
|
||||
if (!LockerManagerFactory.getLockManager().releaseGlobalSessionLock(this)) {
|
||||
throw new TransactionException("UnLock globalSession error, xid = " + this.xid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close and clean.
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
public void closeAndClean() throws TransactionException {
|
||||
close();
|
||||
clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add session lifecycle listener.
|
||||
* @param sessionLifecycleListener the session lifecycle listener
|
||||
*/
|
||||
public void addSessionLifecycleListener(SessionLifecycleListener sessionLifecycleListener) {
|
||||
lifecycleListeners.add(sessionLifecycleListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove session lifecycle listener.
|
||||
* @param sessionLifecycleListener the session lifecycle listener
|
||||
*/
|
||||
public void removeSessionLifecycleListener(SessionLifecycleListener sessionLifecycleListener) {
|
||||
lifecycleListeners.remove(sessionLifecycleListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBranch(BranchSession branchSession) throws TransactionException {
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onAddBranch(this, branchSession);
|
||||
}
|
||||
branchSession.setStatus(BranchStatus.Registered);
|
||||
add(branchSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBranch(BranchSession branchSession) throws TransactionException {
|
||||
// do not unlock if global status in (Committing, CommitRetrying,
|
||||
// AsyncCommitting),
|
||||
// because it's already unlocked in 'DefaultCore.commit()'
|
||||
if (status != Committing && status != CommitRetrying && status != AsyncCommitting) {
|
||||
if (!branchSession.unlock()) {
|
||||
throw new TransactionException(
|
||||
"Unlock branch lock failed, xid = " + this.xid + ", branchId = " + branchSession.getBranchId());
|
||||
}
|
||||
}
|
||||
for (SessionLifecycleListener lifecycleListener : lifecycleListeners) {
|
||||
lifecycleListener.onRemoveBranch(this, branchSession);
|
||||
}
|
||||
remove(branchSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets branch.
|
||||
* @param branchId the branch id
|
||||
* @return the branch
|
||||
*/
|
||||
public BranchSession getBranch(long branchId) {
|
||||
synchronized (branchSessions) {
|
||||
for (BranchSession branchSession : branchSessions) {
|
||||
if (branchSession.getBranchId() == branchId) {
|
||||
return branchSession;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets sorted branches.
|
||||
* @return the sorted branches
|
||||
*/
|
||||
public ArrayList<BranchSession> getSortedBranches() {
|
||||
return new ArrayList<>(branchSessions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets reverse sorted branches.
|
||||
* @return the reverse sorted branches
|
||||
*/
|
||||
public ArrayList<BranchSession> getReverseSortedBranches() {
|
||||
ArrayList<BranchSession> reversed = new ArrayList<>(branchSessions);
|
||||
Collections.reverse(reversed);
|
||||
return reversed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Global session.
|
||||
*/
|
||||
public GlobalSession() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Global session.
|
||||
* @param applicationId the application id
|
||||
* @param transactionServiceGroup the transaction service group
|
||||
* @param transactionName the transaction name
|
||||
* @param timeout the timeout
|
||||
*/
|
||||
public GlobalSession(String applicationId, String transactionServiceGroup, String transactionName, int timeout) {
|
||||
this.transactionId = UUIDGenerator.generateUUID();
|
||||
this.status = GlobalStatus.Begin;
|
||||
|
||||
this.applicationId = applicationId;
|
||||
this.transactionServiceGroup = transactionServiceGroup;
|
||||
this.transactionName = transactionName;
|
||||
this.timeout = timeout;
|
||||
this.xid = XID.generateXID(transactionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets transaction id.
|
||||
* @return the transaction id
|
||||
*/
|
||||
public long getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets transaction id.
|
||||
* @param transactionId the transaction id
|
||||
*/
|
||||
public void setTransactionId(long transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets status.
|
||||
* @return the status
|
||||
*/
|
||||
public GlobalStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets status.
|
||||
* @param status the status
|
||||
*/
|
||||
public void setStatus(GlobalStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets xid.
|
||||
* @return the xid
|
||||
*/
|
||||
public String getXid() {
|
||||
return xid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets xid.
|
||||
* @param xid the xid
|
||||
*/
|
||||
public void setXid(String xid) {
|
||||
this.xid = xid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets application id.
|
||||
* @return the application id
|
||||
*/
|
||||
public String getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets transaction service group.
|
||||
* @return the transaction service group
|
||||
*/
|
||||
public String getTransactionServiceGroup() {
|
||||
return transactionServiceGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets transaction name.
|
||||
* @return the transaction name
|
||||
*/
|
||||
public String getTransactionName() {
|
||||
return transactionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets timeout.
|
||||
* @return the timeout
|
||||
*/
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets begin time.
|
||||
* @return the begin time
|
||||
*/
|
||||
public long getBeginTime() {
|
||||
return beginTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets begin time.
|
||||
* @param beginTime the begin time
|
||||
*/
|
||||
public void setBeginTime(long beginTime) {
|
||||
this.beginTime = beginTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets application data.
|
||||
* @return the application data
|
||||
*/
|
||||
public String getApplicationData() {
|
||||
return applicationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets application data.
|
||||
* @param applicationData the application data
|
||||
*/
|
||||
public void setApplicationData(String applicationData) {
|
||||
this.applicationData = applicationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create global session global session.
|
||||
* @param applicationId the application id
|
||||
* @param txServiceGroup the tx service group
|
||||
* @param txName the tx name
|
||||
* @param timeout the timeout
|
||||
* @return the global session
|
||||
*/
|
||||
public static GlobalSession createGlobalSession(String applicationId, String txServiceGroup, String txName,
|
||||
int timeout) {
|
||||
GlobalSession session = new GlobalSession(applicationId, txServiceGroup, txName, timeout);
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets active.
|
||||
* @param active the active
|
||||
*/
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encode() {
|
||||
byte[] byApplicationIdBytes = applicationId != null ? applicationId.getBytes() : null;
|
||||
|
||||
byte[] byServiceGroupBytes = transactionServiceGroup != null ? transactionServiceGroup.getBytes() : null;
|
||||
|
||||
byte[] byTxNameBytes = transactionName != null ? transactionName.getBytes() : null;
|
||||
|
||||
byte[] xidBytes = xid != null ? xid.getBytes() : null;
|
||||
|
||||
byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes() : null;
|
||||
|
||||
int size = calGlobalSessionSize(byApplicationIdBytes, byServiceGroupBytes, byTxNameBytes, xidBytes,
|
||||
applicationDataBytes);
|
||||
|
||||
if (size > MAX_GLOBAL_SESSION_SIZE) {
|
||||
throw new RuntimeException("global session size exceeded, size : " + size + " maxBranchSessionSize : "
|
||||
+ MAX_GLOBAL_SESSION_SIZE);
|
||||
}
|
||||
ByteBuffer byteBuffer = byteBufferThreadLocal.get();
|
||||
// recycle
|
||||
byteBuffer.clear();
|
||||
|
||||
byteBuffer.putLong(transactionId);
|
||||
byteBuffer.putInt(timeout);
|
||||
if (byApplicationIdBytes != null) {
|
||||
byteBuffer.putShort((short) byApplicationIdBytes.length);
|
||||
byteBuffer.put(byApplicationIdBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putShort((short) 0);
|
||||
}
|
||||
if (byServiceGroupBytes != null) {
|
||||
byteBuffer.putShort((short) byServiceGroupBytes.length);
|
||||
byteBuffer.put(byServiceGroupBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putShort((short) 0);
|
||||
}
|
||||
if (byTxNameBytes != null) {
|
||||
byteBuffer.putShort((short) byTxNameBytes.length);
|
||||
byteBuffer.put(byTxNameBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putShort((short) 0);
|
||||
}
|
||||
if (xidBytes != null) {
|
||||
byteBuffer.putInt(xidBytes.length);
|
||||
byteBuffer.put(xidBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
if (applicationDataBytes != null) {
|
||||
byteBuffer.putInt(applicationDataBytes.length);
|
||||
byteBuffer.put(applicationDataBytes);
|
||||
}
|
||||
else {
|
||||
byteBuffer.putInt(0);
|
||||
}
|
||||
|
||||
byteBuffer.putLong(beginTime);
|
||||
byteBuffer.put((byte) status.getCode());
|
||||
byteBuffer.flip();
|
||||
byte[] result = new byte[byteBuffer.limit()];
|
||||
byteBuffer.get(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private int calGlobalSessionSize(byte[] byApplicationIdBytes, byte[] byServiceGroupBytes, byte[] byTxNameBytes,
|
||||
byte[] xidBytes, byte[] applicationDataBytes) {
|
||||
final int size = 8 // transactionId
|
||||
+ 4 // timeout
|
||||
+ 2 // byApplicationIdBytes.length
|
||||
+ 2 // byServiceGroupBytes.length
|
||||
+ 2 // byTxNameBytes.length
|
||||
+ 4 // xidBytes.length
|
||||
+ 4 // applicationDataBytes.length
|
||||
+ 8 // beginTime
|
||||
+ 1 // statusCode
|
||||
+ (byApplicationIdBytes == null ? 0 : byApplicationIdBytes.length)
|
||||
+ (byServiceGroupBytes == null ? 0 : byServiceGroupBytes.length)
|
||||
+ (byTxNameBytes == null ? 0 : byTxNameBytes.length) + (xidBytes == null ? 0 : xidBytes.length)
|
||||
+ (applicationDataBytes == null ? 0 : applicationDataBytes.length);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(byte[] a) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(a);
|
||||
this.transactionId = byteBuffer.getLong();
|
||||
this.timeout = byteBuffer.getInt();
|
||||
short applicationIdLen = byteBuffer.getShort();
|
||||
if (applicationIdLen > 0) {
|
||||
byte[] byApplicationId = new byte[applicationIdLen];
|
||||
byteBuffer.get(byApplicationId);
|
||||
this.applicationId = new String(byApplicationId);
|
||||
}
|
||||
short serviceGroupLen = byteBuffer.getShort();
|
||||
if (serviceGroupLen > 0) {
|
||||
byte[] byServiceGroup = new byte[serviceGroupLen];
|
||||
byteBuffer.get(byServiceGroup);
|
||||
this.transactionServiceGroup = new String(byServiceGroup);
|
||||
}
|
||||
short txNameLen = byteBuffer.getShort();
|
||||
if (txNameLen > 0) {
|
||||
byte[] byTxName = new byte[txNameLen];
|
||||
byteBuffer.get(byTxName);
|
||||
this.transactionName = new String(byTxName);
|
||||
}
|
||||
int xidLen = byteBuffer.getInt();
|
||||
if (xidLen > 0) {
|
||||
byte[] xidBytes = new byte[xidLen];
|
||||
byteBuffer.get(xidBytes);
|
||||
this.xid = new String(xidBytes);
|
||||
}
|
||||
int applicationDataLen = byteBuffer.getInt();
|
||||
if (applicationDataLen > 0) {
|
||||
byte[] applicationDataLenBytes = new byte[applicationDataLen];
|
||||
byteBuffer.get(applicationDataLenBytes);
|
||||
this.applicationData = new String(applicationDataLenBytes);
|
||||
}
|
||||
|
||||
this.beginTime = byteBuffer.getLong();
|
||||
this.status = GlobalStatus.get(byteBuffer.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Has branch boolean.
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean hasBranch() {
|
||||
return branchSessions.size() > 0;
|
||||
}
|
||||
|
||||
public void lock() throws TransactionException {
|
||||
globalSessionLock.lock();
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
globalSessionLock.unlock();
|
||||
}
|
||||
|
||||
private static class GlobalSessionLock {
|
||||
|
||||
private Lock globalSessionLock = new ReentrantLock();
|
||||
|
||||
private static final int GLOBAL_SESSION_LOCK_TIME_OUT_MILLS = 2 * 1000;
|
||||
|
||||
public void lock() throws TransactionException {
|
||||
try {
|
||||
if (globalSessionLock.tryLock(GLOBAL_SESSION_LOCK_TIME_OUT_MILLS, TimeUnit.MILLISECONDS)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOGGER.error("Interrupted error", e);
|
||||
}
|
||||
throw new GlobalTransactionException(TransactionExceptionCode.FailedLockGlobalTranscation,
|
||||
"Lock global session failed");
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
globalSessionLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface LockRunnable {
|
||||
|
||||
void run() throws TransactionException;
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface LockCallable<V> {
|
||||
|
||||
V call() throws TransactionException;
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<BranchSession> getBranchSessions() {
|
||||
return branchSessions;
|
||||
}
|
||||
|
||||
public void asyncCommit() throws TransactionException {
|
||||
this.addSessionLifecycleListener(SessionHolder.getAsyncCommittingSessionManager());
|
||||
SessionHolder.getAsyncCommittingSessionManager().addGlobalSession(this);
|
||||
this.changeStatus(GlobalStatus.AsyncCommitting);
|
||||
}
|
||||
|
||||
public void queueToRetryCommit() throws TransactionException {
|
||||
this.addSessionLifecycleListener(SessionHolder.getRetryCommittingSessionManager());
|
||||
SessionHolder.getRetryCommittingSessionManager().addGlobalSession(this);
|
||||
this.changeStatus(GlobalStatus.CommitRetrying);
|
||||
}
|
||||
|
||||
public void queueToRetryRollback() throws TransactionException {
|
||||
this.addSessionLifecycleListener(SessionHolder.getRetryRollbackingSessionManager());
|
||||
SessionHolder.getRetryRollbackingSessionManager().addGlobalSession(this);
|
||||
GlobalStatus currentStatus = this.getStatus();
|
||||
if (SessionHelper.isTimeoutGlobalStatus(currentStatus)) {
|
||||
this.changeStatus(GlobalStatus.TimeoutRollbackRetrying);
|
||||
}
|
||||
else {
|
||||
this.changeStatus(GlobalStatus.RollbackRetrying);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.TransactionException;
|
||||
|
||||
/**
|
||||
* The Functional Interface Global session handler
|
||||
*
|
||||
* @author wang.liang
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface GlobalSessionHandler {
|
||||
|
||||
/**
|
||||
* Handle global session.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void handle(GlobalSession globalSession) throws TransactionException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.TransactionException;
|
||||
|
||||
/**
|
||||
* The interface Lockable.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public interface Lockable {
|
||||
|
||||
/**
|
||||
* Lock boolean.
|
||||
* @return the boolean
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
boolean lock() throws TransactionException;
|
||||
|
||||
/**
|
||||
* Unlock boolean.
|
||||
* @return the boolean
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
boolean unlock() throws TransactionException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
/**
|
||||
* Service contains states which can be reloaded.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public interface Reloadable {
|
||||
|
||||
/**
|
||||
* Reload states.
|
||||
*/
|
||||
void reload();
|
||||
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
|
||||
/**
|
||||
* The type Session condition.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public class SessionCondition {
|
||||
|
||||
private Long transactionId;
|
||||
|
||||
private String xid;
|
||||
|
||||
private GlobalStatus status;
|
||||
|
||||
private GlobalStatus[] statuses;
|
||||
|
||||
private long overTimeAliveMills;
|
||||
|
||||
/**
|
||||
* Instantiates a new Session condition.
|
||||
*/
|
||||
public SessionCondition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Session condition.
|
||||
* @param xid the xid
|
||||
*/
|
||||
public SessionCondition(String xid) {
|
||||
this.xid = xid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Session condition.
|
||||
* @param status the status
|
||||
*/
|
||||
public SessionCondition(GlobalStatus status) {
|
||||
this.status = status;
|
||||
statuses = new GlobalStatus[] { status };
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Session condition.
|
||||
* @param statuses the statuses
|
||||
*/
|
||||
public SessionCondition(GlobalStatus[] statuses) {
|
||||
this.statuses = statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Session condition.
|
||||
* @param overTimeAliveMills the over time alive mills
|
||||
*/
|
||||
public SessionCondition(long overTimeAliveMills) {
|
||||
this.overTimeAliveMills = overTimeAliveMills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets status.
|
||||
* @return the status
|
||||
*/
|
||||
public GlobalStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets status.
|
||||
* @param status the status
|
||||
*/
|
||||
public void setStatus(GlobalStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets over time alive mills.
|
||||
* @return the over time alive mills
|
||||
*/
|
||||
public long getOverTimeAliveMills() {
|
||||
return overTimeAliveMills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets over time alive mills.
|
||||
* @param overTimeAliveMills the over time alive mills
|
||||
*/
|
||||
public void setOverTimeAliveMills(long overTimeAliveMills) {
|
||||
this.overTimeAliveMills = overTimeAliveMills;
|
||||
}
|
||||
|
||||
public Long getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(Long transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public String getXid() {
|
||||
return xid;
|
||||
}
|
||||
|
||||
public void setXid(String xid) {
|
||||
this.xid = xid;
|
||||
}
|
||||
|
||||
public GlobalStatus[] getStatuses() {
|
||||
return statuses;
|
||||
}
|
||||
|
||||
public void setStatuses(GlobalStatus[] statuses) {
|
||||
this.statuses = statuses;
|
||||
}
|
||||
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchType;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.server.UUIDGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
/**
|
||||
* The type Session helper.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public class SessionHelper {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SessionHelper.class);
|
||||
|
||||
private SessionHelper() {
|
||||
}
|
||||
|
||||
public static BranchSession newBranchByGlobal(GlobalSession globalSession, BranchType branchType, String resourceId,
|
||||
String lockKeys, String clientId) {
|
||||
return newBranchByGlobal(globalSession, branchType, resourceId, null, lockKeys, clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* New branch by global branch session.
|
||||
* @param globalSession the global session
|
||||
* @param branchType the branch type
|
||||
* @param resourceId the resource id
|
||||
* @param lockKeys the lock keys
|
||||
* @param clientId the client id
|
||||
* @return the branch session
|
||||
*/
|
||||
public static BranchSession newBranchByGlobal(GlobalSession globalSession, BranchType branchType, String resourceId,
|
||||
String applicationData, String lockKeys, String clientId) {
|
||||
BranchSession branchSession = new BranchSession();
|
||||
|
||||
branchSession.setXid(globalSession.getXid());
|
||||
branchSession.setTransactionId(globalSession.getTransactionId());
|
||||
branchSession.setBranchId(UUIDGenerator.generateUUID());
|
||||
branchSession.setBranchType(branchType);
|
||||
branchSession.setResourceId(resourceId);
|
||||
branchSession.setLockKey(lockKeys);
|
||||
branchSession.setClientId(clientId);
|
||||
branchSession.setApplicationData(applicationData);
|
||||
|
||||
return branchSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* New branch
|
||||
* @param branchType the branch type
|
||||
* @param xid Transaction id.
|
||||
* @param branchId Branch id.
|
||||
* @param resourceId Resource id.
|
||||
* @param applicationData Application data bind with this branch.
|
||||
* @return the branch session
|
||||
*/
|
||||
public static BranchSession newBranch(BranchType branchType, String xid, long branchId, String resourceId,
|
||||
String applicationData) {
|
||||
BranchSession branchSession = new BranchSession();
|
||||
branchSession.setXid(xid);
|
||||
branchSession.setBranchId(branchId);
|
||||
branchSession.setBranchType(branchType);
|
||||
branchSession.setResourceId(resourceId);
|
||||
branchSession.setApplicationData(applicationData);
|
||||
return branchSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* End committed.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
public static void endCommitted(GlobalSession globalSession) throws TransactionException {
|
||||
globalSession.changeStatus(GlobalStatus.Committed);
|
||||
globalSession.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* End commit failed.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
public static void endCommitFailed(GlobalSession globalSession) throws TransactionException {
|
||||
globalSession.changeStatus(GlobalStatus.CommitFailed);
|
||||
globalSession.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* End rollbacked.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
public static void endRollbacked(GlobalSession globalSession) throws TransactionException {
|
||||
GlobalStatus currentStatus = globalSession.getStatus();
|
||||
if (isTimeoutGlobalStatus(currentStatus)) {
|
||||
globalSession.changeStatus(GlobalStatus.TimeoutRollbacked);
|
||||
}
|
||||
else {
|
||||
globalSession.changeStatus(GlobalStatus.Rollbacked);
|
||||
}
|
||||
globalSession.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* End rollback failed.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
public static void endRollbackFailed(GlobalSession globalSession) throws TransactionException {
|
||||
GlobalStatus currentStatus = globalSession.getStatus();
|
||||
if (isTimeoutGlobalStatus(currentStatus)) {
|
||||
globalSession.changeStatus(GlobalStatus.TimeoutRollbackFailed);
|
||||
}
|
||||
else {
|
||||
globalSession.changeStatus(GlobalStatus.RollbackFailed);
|
||||
}
|
||||
globalSession.end();
|
||||
}
|
||||
|
||||
public static boolean isTimeoutGlobalStatus(GlobalStatus status) {
|
||||
return status == GlobalStatus.TimeoutRollbacked || status == GlobalStatus.TimeoutRollbackFailed
|
||||
|| status == GlobalStatus.TimeoutRollbacking || status == GlobalStatus.TimeoutRollbackRetrying;
|
||||
}
|
||||
|
||||
/**
|
||||
* Foreach global sessions.
|
||||
* @param sessions the global sessions
|
||||
* @param handler the handler
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public static void forEach(Collection<GlobalSession> sessions, GlobalSessionHandler handler) {
|
||||
for (GlobalSession globalSession : sessions) {
|
||||
try {
|
||||
MDC.put(RootContext.MDC_KEY_XID, globalSession.getXid());
|
||||
handler.handle(globalSession);
|
||||
}
|
||||
catch (Throwable th) {
|
||||
LOGGER.error("handle global session failed: {}", globalSession.getXid(), th);
|
||||
}
|
||||
finally {
|
||||
MDC.remove(RootContext.MDC_KEY_XID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Foreach branch sessions.
|
||||
* @param sessions the branch session
|
||||
* @param handler the handler
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public static Boolean forEach(Collection<BranchSession> sessions, BranchSessionHandler handler)
|
||||
throws TransactionException {
|
||||
Boolean result;
|
||||
for (BranchSession branchSession : sessions) {
|
||||
try {
|
||||
MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId()));
|
||||
result = handler.handle(branchSession);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
MDC.remove(RootContext.MDC_KEY_BRANCH_ID);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+441
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import io.seata.common.exception.ShouldNeverHappenException;
|
||||
import io.seata.common.exception.StoreException;
|
||||
import io.seata.common.loader.EnhancedServiceLoader;
|
||||
import io.seata.common.util.CollectionUtils;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import io.seata.config.Configuration;
|
||||
import io.seata.config.ConfigurationFactory;
|
||||
import io.seata.core.constants.ConfigurationKeys;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.core.store.StoreMode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static io.seata.common.Constants.ASYNC_COMMITTING;
|
||||
import static io.seata.common.Constants.RETRY_COMMITTING;
|
||||
import static io.seata.common.Constants.RETRY_ROLLBACKING;
|
||||
import static io.seata.common.Constants.TX_TIMEOUT_CHECK;
|
||||
import static io.seata.common.Constants.UNDOLOG_DELETE;
|
||||
|
||||
/**
|
||||
* The type Session holder.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public class SessionHolder {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SessionHolder.class);
|
||||
|
||||
/**
|
||||
* The constant CONFIG.
|
||||
*/
|
||||
protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
|
||||
|
||||
/**
|
||||
* The constant ROOT_SESSION_MANAGER_NAME.
|
||||
*/
|
||||
public static final String ROOT_SESSION_MANAGER_NAME = "root.data";
|
||||
|
||||
/**
|
||||
* The constant ASYNC_COMMITTING_SESSION_MANAGER_NAME.
|
||||
*/
|
||||
public static final String ASYNC_COMMITTING_SESSION_MANAGER_NAME = "async.commit.data";
|
||||
|
||||
/**
|
||||
* The constant RETRY_COMMITTING_SESSION_MANAGER_NAME.
|
||||
*/
|
||||
public static final String RETRY_COMMITTING_SESSION_MANAGER_NAME = "retry.commit.data";
|
||||
|
||||
/**
|
||||
* The constant RETRY_ROLLBACKING_SESSION_MANAGER_NAME.
|
||||
*/
|
||||
public static final String RETRY_ROLLBACKING_SESSION_MANAGER_NAME = "retry.rollback.data";
|
||||
|
||||
/**
|
||||
* The default session store dir
|
||||
*/
|
||||
public static final String DEFAULT_SESSION_STORE_FILE_DIR = "sessionStore";
|
||||
|
||||
private static SessionManager ROOT_SESSION_MANAGER;
|
||||
|
||||
private static SessionManager ASYNC_COMMITTING_SESSION_MANAGER;
|
||||
|
||||
private static SessionManager RETRY_COMMITTING_SESSION_MANAGER;
|
||||
|
||||
private static SessionManager RETRY_ROLLBACKING_SESSION_MANAGER;
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* @param mode the store mode: file, db
|
||||
* @throws IOException the io exception
|
||||
*/
|
||||
public static void init(String mode) {
|
||||
if (StringUtils.isBlank(mode)) {
|
||||
mode = CONFIG.getConfig(ConfigurationKeys.STORE_MODE);
|
||||
}
|
||||
StoreMode storeMode = StoreMode.get(mode);
|
||||
if (StoreMode.DB.equals(storeMode)) {
|
||||
ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName());
|
||||
ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
|
||||
new Object[] { ASYNC_COMMITTING_SESSION_MANAGER_NAME });
|
||||
RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
|
||||
new Object[] { RETRY_COMMITTING_SESSION_MANAGER_NAME });
|
||||
RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.getName(),
|
||||
new Object[] { RETRY_ROLLBACKING_SESSION_MANAGER_NAME });
|
||||
}
|
||||
else if (StoreMode.FILE.equals(storeMode)) {
|
||||
String sessionStorePath = CONFIG.getConfig(ConfigurationKeys.STORE_FILE_DIR,
|
||||
DEFAULT_SESSION_STORE_FILE_DIR);
|
||||
if (StringUtils.isBlank(sessionStorePath)) {
|
||||
throw new StoreException("the {store.file.dir} is empty.");
|
||||
}
|
||||
ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.FILE.getName(),
|
||||
new Object[] { ROOT_SESSION_MANAGER_NAME, sessionStorePath });
|
||||
ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.FILE.getName(), new Class[] { String.class, String.class },
|
||||
new Object[] { ASYNC_COMMITTING_SESSION_MANAGER_NAME, null });
|
||||
RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.FILE.getName(), new Class[] { String.class, String.class },
|
||||
new Object[] { RETRY_COMMITTING_SESSION_MANAGER_NAME, null });
|
||||
RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.FILE.getName(), new Class[] { String.class, String.class },
|
||||
new Object[] { RETRY_ROLLBACKING_SESSION_MANAGER_NAME, null });
|
||||
}
|
||||
else if (StoreMode.REDIS.equals(storeMode)) {
|
||||
ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.REDIS.getName());
|
||||
ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.REDIS.getName(), new Object[] { ASYNC_COMMITTING_SESSION_MANAGER_NAME });
|
||||
RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.REDIS.getName(), new Object[] { RETRY_COMMITTING_SESSION_MANAGER_NAME });
|
||||
RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class,
|
||||
StoreMode.REDIS.getName(), new Object[] { RETRY_ROLLBACKING_SESSION_MANAGER_NAME });
|
||||
}
|
||||
else {
|
||||
// unknown store
|
||||
throw new IllegalArgumentException("unknown store mode:" + mode);
|
||||
}
|
||||
reload(storeMode);
|
||||
}
|
||||
|
||||
// region reload
|
||||
|
||||
/**
|
||||
* Reload.
|
||||
*/
|
||||
protected static void reload(StoreMode storeMode) {
|
||||
if (ROOT_SESSION_MANAGER instanceof Reloadable) {
|
||||
((Reloadable) ROOT_SESSION_MANAGER).reload();
|
||||
}
|
||||
|
||||
Collection<GlobalSession> allSessions = ROOT_SESSION_MANAGER.allSessions();
|
||||
if (CollectionUtils.isNotEmpty(allSessions)) {
|
||||
List<GlobalSession> removeGlobalSessions = new ArrayList<>();
|
||||
Iterator<GlobalSession> iterator = allSessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
GlobalSession globalSession = iterator.next();
|
||||
GlobalStatus globalStatus = globalSession.getStatus();
|
||||
switch (globalStatus) {
|
||||
case UnKnown:
|
||||
case Committed:
|
||||
case CommitFailed:
|
||||
case Rollbacked:
|
||||
case RollbackFailed:
|
||||
case TimeoutRollbacked:
|
||||
case TimeoutRollbackFailed:
|
||||
case Finished:
|
||||
removeGlobalSessions.add(globalSession);
|
||||
break;
|
||||
case AsyncCommitting:
|
||||
if (storeMode == StoreMode.FILE) {
|
||||
queueToAsyncCommitting(globalSession);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
if (storeMode == StoreMode.FILE) {
|
||||
lockBranchSessions(globalSession.getSortedBranches());
|
||||
|
||||
switch (globalStatus) {
|
||||
case Committing:
|
||||
case CommitRetrying:
|
||||
queueToRetryCommit(globalSession);
|
||||
break;
|
||||
case Rollbacking:
|
||||
case RollbackRetrying:
|
||||
case TimeoutRollbacking:
|
||||
case TimeoutRollbackRetrying:
|
||||
queueToRetryRollback(globalSession);
|
||||
break;
|
||||
case Begin:
|
||||
globalSession.setActive(true);
|
||||
break;
|
||||
default:
|
||||
throw new ShouldNeverHappenException("NOT properly handled " + globalStatus);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (GlobalSession globalSession : removeGlobalSessions) {
|
||||
removeInErrorState(globalSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeInErrorState(GlobalSession globalSession) {
|
||||
try {
|
||||
LOGGER.warn("The global session should NOT be {}, remove it. xid = {}", globalSession.getStatus(),
|
||||
globalSession.getXid());
|
||||
ROOT_SESSION_MANAGER.removeGlobalSession(globalSession);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("Remove global session succeed, xid = {}, status = {}", globalSession.getXid(),
|
||||
globalSession.getStatus());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOGGER.error("Remove global session failed, xid = {}, status = {}", globalSession.getXid(),
|
||||
globalSession.getStatus(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void queueToAsyncCommitting(GlobalSession globalSession) {
|
||||
try {
|
||||
globalSession.addSessionLifecycleListener(getAsyncCommittingSessionManager());
|
||||
getAsyncCommittingSessionManager().addGlobalSession(globalSession);
|
||||
}
|
||||
catch (TransactionException e) {
|
||||
throw new ShouldNeverHappenException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void lockBranchSessions(ArrayList<BranchSession> branchSessions) {
|
||||
branchSessions.forEach(branchSession -> {
|
||||
try {
|
||||
branchSession.lock();
|
||||
}
|
||||
catch (TransactionException e) {
|
||||
throw new ShouldNeverHappenException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void queueToRetryCommit(GlobalSession globalSession) {
|
||||
try {
|
||||
globalSession.addSessionLifecycleListener(getRetryCommittingSessionManager());
|
||||
getRetryCommittingSessionManager().addGlobalSession(globalSession);
|
||||
}
|
||||
catch (TransactionException e) {
|
||||
throw new ShouldNeverHappenException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void queueToRetryRollback(GlobalSession globalSession) {
|
||||
try {
|
||||
globalSession.addSessionLifecycleListener(getRetryRollbackingSessionManager());
|
||||
getRetryRollbackingSessionManager().addGlobalSession(globalSession);
|
||||
}
|
||||
catch (TransactionException e) {
|
||||
throw new ShouldNeverHappenException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region get session manager
|
||||
|
||||
/**
|
||||
* Gets root session manager.
|
||||
* @return the root session manager
|
||||
*/
|
||||
public static SessionManager getRootSessionManager() {
|
||||
if (ROOT_SESSION_MANAGER == null) {
|
||||
throw new ShouldNeverHappenException("SessionManager is NOT init!");
|
||||
}
|
||||
return ROOT_SESSION_MANAGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets async committing session manager.
|
||||
* @return the async committing session manager
|
||||
*/
|
||||
public static SessionManager getAsyncCommittingSessionManager() {
|
||||
if (ASYNC_COMMITTING_SESSION_MANAGER == null) {
|
||||
throw new ShouldNeverHappenException("SessionManager is NOT init!");
|
||||
}
|
||||
return ASYNC_COMMITTING_SESSION_MANAGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets retry committing session manager.
|
||||
* @return the retry committing session manager
|
||||
*/
|
||||
public static SessionManager getRetryCommittingSessionManager() {
|
||||
if (RETRY_COMMITTING_SESSION_MANAGER == null) {
|
||||
throw new ShouldNeverHappenException("SessionManager is NOT init!");
|
||||
}
|
||||
return RETRY_COMMITTING_SESSION_MANAGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets retry rollbacking session manager.
|
||||
* @return the retry rollbacking session manager
|
||||
*/
|
||||
public static SessionManager getRetryRollbackingSessionManager() {
|
||||
if (RETRY_ROLLBACKING_SESSION_MANAGER == null) {
|
||||
throw new ShouldNeverHappenException("SessionManager is NOT init!");
|
||||
}
|
||||
return RETRY_ROLLBACKING_SESSION_MANAGER;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Find global session.
|
||||
* @param xid the xid
|
||||
* @return the global session
|
||||
*/
|
||||
public static GlobalSession findGlobalSession(String xid) {
|
||||
return findGlobalSession(xid, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find global session.
|
||||
* @param xid the xid
|
||||
* @param withBranchSessions the withBranchSessions
|
||||
* @return the global session
|
||||
*/
|
||||
public static GlobalSession findGlobalSession(String xid, boolean withBranchSessions) {
|
||||
return getRootSessionManager().findGlobalSession(xid, withBranchSessions);
|
||||
}
|
||||
|
||||
/**
|
||||
* lock and execute
|
||||
* @param globalSession the global session
|
||||
* @param lockCallable the lock Callable
|
||||
* @return the value
|
||||
*/
|
||||
public static <T> T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable<T> lockCallable)
|
||||
throws TransactionException {
|
||||
return getRootSessionManager().lockAndExecute(globalSession, lockCallable);
|
||||
}
|
||||
|
||||
/**
|
||||
* retry rollbacking lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean retryRollbackingLock() {
|
||||
return getRootSessionManager().scheduledLock(RETRY_ROLLBACKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* retry committing lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean retryCommittingLock() {
|
||||
return getRootSessionManager().scheduledLock(RETRY_COMMITTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* async committing lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean asyncCommittingLock() {
|
||||
return getRootSessionManager().scheduledLock(ASYNC_COMMITTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* tx timeout check lOck
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean txTimeoutCheckLock() {
|
||||
return getRootSessionManager().scheduledLock(TX_TIMEOUT_CHECK);
|
||||
}
|
||||
|
||||
/**
|
||||
* undolog delete lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean undoLogDeleteLock() {
|
||||
return getRootSessionManager().scheduledLock(UNDOLOG_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* un retry rollbacking lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean unRetryRollbackingLock() {
|
||||
return getRootSessionManager().unScheduledLock(RETRY_ROLLBACKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* un retry committing lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean unRetryCommittingLock() {
|
||||
return getRootSessionManager().unScheduledLock(RETRY_COMMITTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* un async committing lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean unAsyncCommittingLock() {
|
||||
return getRootSessionManager().unScheduledLock(ASYNC_COMMITTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* un tx timeout check lOck
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean unTxTimeoutCheckLock() {
|
||||
return getRootSessionManager().unScheduledLock(TX_TIMEOUT_CHECK);
|
||||
}
|
||||
|
||||
/**
|
||||
* un undolog delete lock
|
||||
* @return the boolean
|
||||
*/
|
||||
public static boolean unUndoLogDeleteLock() {
|
||||
return getRootSessionManager().unScheduledLock(UNDOLOG_DELETE);
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if (ROOT_SESSION_MANAGER != null) {
|
||||
ROOT_SESSION_MANAGER.destroy();
|
||||
}
|
||||
if (ASYNC_COMMITTING_SESSION_MANAGER != null) {
|
||||
ASYNC_COMMITTING_SESSION_MANAGER.destroy();
|
||||
}
|
||||
if (RETRY_COMMITTING_SESSION_MANAGER != null) {
|
||||
RETRY_COMMITTING_SESSION_MANAGER.destroy();
|
||||
}
|
||||
if (RETRY_ROLLBACKING_SESSION_MANAGER != null) {
|
||||
RETRY_ROLLBACKING_SESSION_MANAGER.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
|
||||
/**
|
||||
* The interface Session lifecycle.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public interface SessionLifecycle {
|
||||
|
||||
/**
|
||||
* Begin.
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void begin() throws TransactionException;
|
||||
|
||||
/**
|
||||
* Change status.
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void changeStatus(GlobalStatus status) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Change branch status.
|
||||
* @param branchSession the branch session
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void changeBranchStatus(BranchSession branchSession, BranchStatus status) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Add branch.
|
||||
* @param branchSession the branch session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void addBranch(BranchSession branchSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Remove branch.
|
||||
* @param branchSession the branch session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void removeBranch(BranchSession branchSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Is active boolean.
|
||||
* @return the boolean
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Close.
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void close() throws TransactionException;
|
||||
|
||||
/**
|
||||
* End.
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void end() throws TransactionException;
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
|
||||
/**
|
||||
* The interface Session lifecycle listener.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public interface SessionLifecycleListener {
|
||||
|
||||
/**
|
||||
* On begin.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onBegin(GlobalSession globalSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* On status change.
|
||||
* @param globalSession the global session
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onStatusChange(GlobalSession globalSession, GlobalStatus status) throws TransactionException;
|
||||
|
||||
/**
|
||||
* On branch status change.
|
||||
* @param globalSession the global session
|
||||
* @param branchSession the branch session
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onBranchStatusChange(GlobalSession globalSession, BranchSession branchSession, BranchStatus status)
|
||||
throws TransactionException;
|
||||
|
||||
/**
|
||||
* On add branch.
|
||||
* @param globalSession the global session
|
||||
* @param branchSession the branch session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onAddBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* On remove branch.
|
||||
* @param globalSession the global session
|
||||
* @param branchSession the branch session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onRemoveBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* On close.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onClose(GlobalSession globalSession) throws TransactionException;
|
||||
|
||||
/**
|
||||
* On end.
|
||||
* @param globalSession the global session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void onEnd(GlobalSession globalSession) throws TransactionException;
|
||||
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.seata.server.session;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import io.seata.core.exception.TransactionException;
|
||||
import io.seata.core.model.BranchStatus;
|
||||
import io.seata.core.model.GlobalStatus;
|
||||
import io.seata.core.rpc.Disposable;
|
||||
|
||||
/**
|
||||
* The interface Session manager.
|
||||
*
|
||||
* @author sharajava
|
||||
*/
|
||||
public interface SessionManager extends SessionLifecycleListener, Disposable {
|
||||
|
||||
/**
|
||||
* Add global session.
|
||||
* @param session the session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void addGlobalSession(GlobalSession session) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Find global session global session.
|
||||
* @param xid the xid
|
||||
* @return the global session
|
||||
*/
|
||||
GlobalSession findGlobalSession(String xid);
|
||||
|
||||
/**
|
||||
* Find global session global session.
|
||||
* @param xid the xid
|
||||
* @param withBranchSessions the withBranchSessions
|
||||
* @return the global session
|
||||
*/
|
||||
GlobalSession findGlobalSession(String xid, boolean withBranchSessions);
|
||||
|
||||
/**
|
||||
* Update global session status.
|
||||
* @param session the session
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Remove global session.
|
||||
* @param session the session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void removeGlobalSession(GlobalSession session) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Add branch session.
|
||||
* @param globalSession the global session
|
||||
* @param session the session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Update branch session status.
|
||||
* @param session the session
|
||||
* @param status the status
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void updateBranchSessionStatus(BranchSession session, BranchStatus status) throws TransactionException;
|
||||
|
||||
/**
|
||||
* Remove branch session.
|
||||
* @param globalSession the global session
|
||||
* @param session the session
|
||||
* @throws TransactionException the transaction exception
|
||||
*/
|
||||
void removeBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException;
|
||||
|
||||
/**
|
||||
* All sessions collection.
|
||||
* @return the collection
|
||||
*/
|
||||
Collection<GlobalSession> allSessions();
|
||||
|
||||
/**
|
||||
* Find global sessions list.
|
||||
* @param condition the condition
|
||||
* @return the list
|
||||
*/
|
||||
List<GlobalSession> findGlobalSessions(SessionCondition condition);
|
||||
|
||||
/**
|
||||
* lock and execute
|
||||
* @param globalSession the global session
|
||||
* @param lockCallable the lock Callable
|
||||
* @return the value
|
||||
*/
|
||||
<T> T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable<T> lockCallable)
|
||||
throws TransactionException;
|
||||
|
||||
/**
|
||||
* scheduled lock
|
||||
* @param key the lock key
|
||||
* @return the boolean
|
||||
*/
|
||||
default boolean scheduledLock(String key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* un scheduled lock
|
||||
* @param key the lock key
|
||||
* @return the boolean
|
||||
*/
|
||||
default boolean unScheduledLock(String key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user