package io.eguan.dtx;
/*
* #%L
* Project eguan
* %%
* Copyright (C) 2012 - 2017 Oodrive
* %%
* 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.
* #L%
*/
import static io.eguan.dtx.DtxNodeState.STARTED;
import static io.eguan.dtx.DtxResourceManagerState.UNDETERMINED;
import io.eguan.dtx.events.DtxClusterEvent;
import io.eguan.dtx.events.DtxNodeEvent;
import io.eguan.dtx.events.DtxResourceManagerEvent;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import javax.annotation.Nonnull;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
/**
* Handler for all events triggering discovery actions.
*
* @author oodrive
* @author pwehrle
*
*/
final class DiscoveryEventHandler {
/**
* Handles any {@link DtxClusterEvent} and launches discovery where necessary.
*
* @param event
* the input {@link DtxClusterEvent}
* @throws InterruptedException
* if handling is interrupted while waiting on the {@link DtxManager#getStatusReadLock() status lock}
*/
@Subscribe
@AllowConcurrentEvents
public final void handleClusterEvent(@Nonnull final DtxClusterEvent event) throws InterruptedException {
switch (event.getType()) {
case ADDED:
doAdded(event);
break;
case REMOVED:
doRemoved(event);
break;
default:
// nothing
}
}
private final void doAdded(final DtxClusterEvent event) throws InterruptedException {
// gets the context references from the source
final DtxManager dtxManager = event.getSource();
assert (dtxManager != null);
final TransactionManager txMgr = dtxManager.getTxManager();
final ReadLock readLock = dtxManager.getStatusReadLock();
readLock.lockInterruptibly();
try {
if (!STARTED.equals(dtxManager.getStatus())) {
// do nothing
return;
}
// discover status of all local resource managers on newly added node
final HashMap<UUID, Long> discoveryMap = new HashMap<UUID, Long>();
for (final DtxResourceManager currResMgr : txMgr.getRegisteredResourceManagers()) {
final UUID resId = currResMgr.getId();
discoveryMap.put(resId, Long.valueOf(txMgr.getLastCompleteTxIdForResMgr(resId)));
}
dtxManager.discoverResMgrStatus(discoveryMap, event.getNode());
// discover status of all undetermined resource managers on all online nodes
dtxManager.discoverResMgrStatus(txMgr.getUndeterminedResourceManagers());
}
finally {
readLock.unlock();
}
}
private final void doRemoved(@Nonnull final DtxClusterEvent event) throws InterruptedException {
// gets the context references from the source
final DtxManager dtxManager = event.getSource();
assert (dtxManager != null);
final DtxNode node = event.getNode();
final ReadLock readLock = dtxManager.getStatusReadLock();
readLock.lockInterruptibly();
try {
if (!STARTED.equals(dtxManager.getStatus())) {
// do nothing
return;
}
dtxManager.removeClusterMapInfo(node);
}
finally {
readLock.unlock();
}
}
/**
* Handles any {@link DtxResourceManagerEvent} leading to discovery operations including the target resource
* manager.
*
* @param event
* the input {@link DtxResourceManagerEvent}
* @throws InterruptedException
* if handling is interrupted while waiting on the {@link DtxManager#getStatusReadLock() status lock}
*/
@Subscribe
@AllowConcurrentEvents
public final void handleResourceManagerEvent(@Nonnull final DtxResourceManagerEvent event)
throws InterruptedException {
final DtxResourceManagerState newState = event.getNewState();
if (UNDETERMINED != newState) {
// limit discover to undetermined state
return;
}
final DtxManager dtxManager = event.getSource();
assert (dtxManager != null);
final TransactionManager txMgr = dtxManager.getTxManager();
final ReadLock readLock = dtxManager.getStatusReadLock();
readLock.lockInterruptibly();
try {
if (STARTED != dtxManager.getStatus()) {
// do nothing if not started
return;
}
// discover the new resource manager's status on all online nodes
final UUID resId = event.getResourceManagerId();
final HashMap<UUID, Long> discoveryMap = new HashMap<UUID, Long>();
discoveryMap.put(resId, Long.valueOf(txMgr.getLastCompleteTxIdForResMgr(resId)));
dtxManager.discoverResMgrStatus(discoveryMap);
}
finally {
readLock.unlock();
}
}
/**
* Handles any {@link DtxNodeEvent} leading to discovery operations on the target node.
*
* @param event
* the input {@link DtxNodeEvent}
* @throws InterruptedException
* if handling is interrupted while waiting on the {@link DtxManager#getStatusReadLock() status lock}
*/
@Subscribe
@AllowConcurrentEvents
public final void handleDtxNodeEvent(@Nonnull final DtxNodeEvent event) throws InterruptedException {
final DtxNodeState newState = event.getNewState();
if (!STARTED.equals(newState)) {
// do nothing
return;
}
// gets the context references from the source
final DtxManager dtxManager = event.getSource();
assert (dtxManager != null);
final TransactionManager txMgr = dtxManager.getTxManager();
final ReadLock readLock = dtxManager.getStatusReadLock();
readLock.lockInterruptibly();
try {
// goes on to discover synchronization states for all resource managers
final HashMap<UUID, Long> discoveryMap = new HashMap<UUID, Long>();
for (final DtxResourceManager currResMgr : txMgr.getRegisteredResourceManagers()) {
final UUID resId = currResMgr.getId();
discoveryMap.put(resId, Long.valueOf(txMgr.getLastCompleteTxIdForResMgr(resId)));
}
dtxManager.discoverResMgrStatus(discoveryMap);
}
finally {
readLock.unlock();
}
}
}