com.hazelcast.transaction.impl.xa.XAService Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.transaction.impl.xa;
import com.hazelcast.core.DistributedObject;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.spi.ManagedService;
import com.hazelcast.spi.MigrationAwareService;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.PartitionMigrationEvent;
import com.hazelcast.spi.PartitionReplicationEvent;
import com.hazelcast.spi.RemoteService;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.spi.partition.MigrationEndpoint;
import com.hazelcast.transaction.TransactionContext;
import com.hazelcast.transaction.impl.xa.operations.XaReplicationOperation;
import javax.transaction.xa.Xid;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides XAResource to the user via proxyService
* Holds all prepared state xa transactions
*/
public class XAService implements ManagedService, RemoteService, MigrationAwareService {
public static final String SERVICE_NAME = "hz:impl:xaService";
private final NodeEngineImpl nodeEngine;
private final XAResourceImpl xaResource;
private final ConcurrentMap> transactions =
new ConcurrentHashMap>();
public XAService(NodeEngineImpl nodeEngine) {
this.nodeEngine = nodeEngine;
this.xaResource = new XAResourceImpl(nodeEngine, this);
}
@Override
public void init(NodeEngine nodeEngine, Properties properties) {
}
@Override
public void reset() {
}
@Override
public void shutdown(boolean terminate) {
}
@Override
public DistributedObject createDistributedObject(String objectName) {
return xaResource;
}
@Override
public void destroyDistributedObject(String objectName) {
}
public TransactionContext newXATransactionContext(Xid xid, String ownerUuid, int timeout, boolean originatedFromClient) {
return new XATransactionContextImpl(nodeEngine, xid, ownerUuid, timeout, originatedFromClient);
}
public void putTransaction(XATransaction transaction) {
SerializableXID xid = transaction.getXid();
List list = transactions.get(xid);
if (list == null) {
list = new CopyOnWriteArrayList();
transactions.put(xid, list);
}
list.add(transaction);
}
public List removeTransactions(SerializableXID xid) {
return transactions.remove(xid);
}
public Set getPreparedXids() {
return transactions.keySet();
}
//Migration related methods
@Override
public Operation prepareReplicationOperation(PartitionReplicationEvent event) {
if (event.getReplicaIndex() > 1) {
return null;
}
List migrationData = new ArrayList();
InternalPartitionService partitionService = nodeEngine.getPartitionService();
for (Map.Entry> entry : transactions.entrySet()) {
SerializableXID xid = entry.getKey();
int partitionId = partitionService.getPartitionId(xid);
List xaTransactionList = entry.getValue();
for (XATransaction xaTransaction : xaTransactionList) {
if (partitionId == event.getPartitionId()) {
migrationData.add(new XATransactionDTO(xaTransaction));
}
}
}
if (migrationData.isEmpty()) {
return null;
} else {
return new XaReplicationOperation(migrationData, event.getPartitionId(), event.getReplicaIndex());
}
}
@Override
public void beforeMigration(PartitionMigrationEvent event) {
}
@Override
public void commitMigration(PartitionMigrationEvent event) {
if (event.getMigrationEndpoint() == MigrationEndpoint.SOURCE) {
int thresholdReplicaIndex = event.getNewReplicaIndex();
if (thresholdReplicaIndex == -1 || thresholdReplicaIndex > 1) {
clearPartitionReplica(event.getPartitionId());
}
}
}
@Override
public void rollbackMigration(PartitionMigrationEvent event) {
if (event.getMigrationEndpoint() == MigrationEndpoint.DESTINATION) {
int thresholdReplicaIndex = event.getCurrentReplicaIndex();
if (thresholdReplicaIndex == -1 || thresholdReplicaIndex > 1) {
clearPartitionReplica(event.getPartitionId());
}
}
}
private void clearPartitionReplica(int partitionId) {
InternalPartitionService partitionService = nodeEngine.getPartitionService();
Iterator>> iterator = transactions.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry> entry = iterator.next();
SerializableXID xid = entry.getKey();
int xidPartitionId = partitionService.getPartitionId(xid);
if (xidPartitionId == partitionId) {
iterator.remove();
}
}
}
}