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.DtxResourceManagerState.LATE; import static io.eguan.dtx.DtxResourceManagerState.SYNCHRONIZING; import static io.eguan.dtx.DtxResourceManagerState.UNDETERMINED; import io.eguan.dtx.events.DtxResourceManagerEvent; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.UUID; import javax.annotation.Nonnull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.eventbus.AllowConcurrentEvents; import com.google.common.eventbus.Subscribe; /** * Event handler for triggering synchronization actions. * * @author oodrive * @author pwehrle * */ public final class SyncEventHandler { private static final Logger LOGGER = LoggerFactory.getLogger(SyncEventHandler.class); /** * Intercepts {@link DtxResourceManagerEvent}s for {@link DtxResourceManagerState#LATE} resource managers and * triggers synchronization. * * @param event * the posted {@link DtxResourceManagerEvent} */ @Subscribe @AllowConcurrentEvents public final void handleDtxResourceManagerEvent(@Nonnull final DtxResourceManagerEvent event) { final DtxResourceManagerState newState = event.getNewState(); if (LATE != newState) { // not late, i.e. do not trigger synchronization return; } final UUID resId = event.getResourceManagerId(); final DtxManager dtxManager = event.getSource(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Triggering synchronization; node=" + dtxManager.getNodeId() + ", resourceId=" + resId); } final TransactionManager txManager = dtxManager.getTxManager(); if (txManager == null) { LOGGER.warn("Transaction manager is null, abandoning synchronization"); return; } txManager.setResManagerSyncState(resId, SYNCHRONIZING); try { long lastLocalTxId = txManager.getLastCompleteTxIdForResMgr(resId); final Map<DtxNode, Long> updateMap = dtxManager.getClusterMapInfo(resId, Long.valueOf(lastLocalTxId)); if (updateMap.isEmpty()) { return; } final long maxTxId = Collections.max(updateMap.values()).longValue(); // TODO: choose update source more wisely final Iterator<DtxNode> nodeIter = updateMap.keySet().iterator(); while (nodeIter.hasNext() && (lastLocalTxId < maxTxId)) { final DtxNode targetNode = nodeIter.next(); final long targetNodeLastTxId = updateMap.get(targetNode).longValue(); if (targetNodeLastTxId > lastLocalTxId) { lastLocalTxId = dtxManager .synchronizeWithNode(resId, targetNode, lastLocalTxId, targetNodeLastTxId); } } } finally { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Synchronization finished; node=" + dtxManager.getNodeId() + ", resourceId=" + resId); } txManager.setResManagerSyncState(resId, UNDETERMINED); } } }