/* * 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.lock; import io.seata.common.XID; import io.seata.common.util.CollectionUtils; import io.seata.common.util.StringUtils; import io.seata.core.exception.TransactionException; import io.seata.core.lock.Locker; import io.seata.core.lock.RowLock; import io.seata.core.model.LockStatus; import io.seata.server.session.BranchSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The type Abstract lock manager. * * @author zhangsen */ public abstract class AbstractLockManager implements LockManager { /** * The constant LOGGER. */ protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLockManager.class); @Override public boolean acquireLock(BranchSession branchSession) throws TransactionException { return acquireLock(branchSession, true, false); } @Override public boolean acquireLock(BranchSession branchSession, boolean autoCommit, boolean skipCheckLock) throws TransactionException { if (branchSession == null) { throw new IllegalArgumentException("branchSession can't be null for memory/file locker."); } String lockKey = branchSession.getLockKey(); if (StringUtils.isNullOrEmpty(lockKey)) { // no lock return true; } // get locks of branch List locks = collectRowLocks(branchSession); if (CollectionUtils.isEmpty(locks)) { // no lock return true; } return getLocker(branchSession).acquireLock(locks, autoCommit, skipCheckLock); } @Override public boolean releaseLock(BranchSession branchSession) throws TransactionException { if (branchSession == null) { throw new IllegalArgumentException("branchSession can't be null for memory/file locker."); } List locks = collectRowLocks(branchSession); try { return getLocker(branchSession).releaseLock(locks); } catch (Exception t) { LOGGER.error("unLock error, branchSession:{}", branchSession, t); return false; } } @Override public boolean isLockable(String xid, String resourceId, String lockKey) throws TransactionException { if (StringUtils.isBlank(lockKey)) { // no lock return true; } List locks = collectRowLocks(lockKey, resourceId, xid); try { return getLocker().isLockable(locks); } catch (Exception t) { LOGGER.error("isLockable error, xid:{} resourceId:{}, lockKey:{}", xid, resourceId, lockKey, t); return false; } } @Override public void cleanAllLocks() throws TransactionException { getLocker().cleanAllLocks(); } /** * Gets locker. * * @return the locker */ protected Locker getLocker() { return getLocker(null); } /** * Gets locker. * * @param branchSession the branch session * @return the locker */ protected abstract Locker getLocker(BranchSession branchSession); @Override public List collectRowLocks(BranchSession branchSession) { if (branchSession == null || StringUtils.isBlank(branchSession.getLockKey())) { return Collections.emptyList(); } String lockKey = branchSession.getLockKey(); String resourceId = branchSession.getResourceId(); String xid = branchSession.getXid(); long transactionId = branchSession.getTransactionId(); long branchId = branchSession.getBranchId(); return collectRowLocks(lockKey, resourceId, xid, transactionId, branchId); } /** * Collect row locks list. * * @param lockKey the lock key * @param resourceId the resource id * @param xid the xid * @return the list */ protected List collectRowLocks(String lockKey, String resourceId, String xid) { return collectRowLocks(lockKey, resourceId, xid, XID.getTransactionId(xid), null); } /** * Collect row locks list. * * @param lockKey the lock key * @param resourceId the resource id * @param xid the xid * @param transactionId the transaction id * @param branchID the branch id * @return the list */ protected List collectRowLocks(String lockKey, String resourceId, String xid, Long transactionId, Long branchID) { List locks = new ArrayList<>(); String[] tableGroupedLockKeys = lockKey.split(";"); for (String tableGroupedLockKey : tableGroupedLockKeys) { int idx = tableGroupedLockKey.indexOf(":"); if (idx < 0) { return locks; } String tableName = tableGroupedLockKey.substring(0, idx); String mergedPKs = tableGroupedLockKey.substring(idx + 1); if (StringUtils.isBlank(mergedPKs)) { return locks; } String[] pks = mergedPKs.split(","); if (pks == null || pks.length == 0) { return locks; } for (String pk : pks) { if (StringUtils.isNotBlank(pk)) { RowLock rowLock = new RowLock(); rowLock.setXid(xid); rowLock.setTransactionId(transactionId); rowLock.setBranchId(branchID); rowLock.setTableName(tableName); rowLock.setPk(pk); rowLock.setResourceId(resourceId); locks.add(rowLock); } } } return locks; } @Override public void updateLockStatus(String xid, LockStatus lockStatus) { this.getLocker().updateLockStatus(xid, lockStatus); } }