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.POST_SYNC_PROCESSING;
import static io.eguan.dtx.DtxResourceManagerState.UNDETERMINED;
import static io.eguan.dtx.DtxResourceManagerState.UP_TO_DATE;
import io.eguan.dtx.events.DtxResourceManagerEvent;
import java.util.HashSet;
import java.util.Set;
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;
/**
* Class for processing post-sync jobs.
*
* @author oodrive
* @author pwehrle
*
*/
final class PostSyncProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(PostSyncProcessor.class);
private final Set<UUID> runningPostProcSet = new HashSet<UUID>();
private final Set<UUID> resetAfterPostProcSet = new HashSet<UUID>();
/**
* Registers the reset of the target resource manager to an {@link DtxResourceManagerState#UNDETERMINED} state after
* completing post-synchronization.
*
* @param resUuid
* the target resource managers {@link UUID}
*/
final void resetAfterPostProc(final UUID resUuid) {
synchronized (runningPostProcSet) {
if (!runningPostProcSet.contains(resUuid)) {
return;
}
synchronized (resetAfterPostProcSet) {
resetAfterPostProcSet.add(resUuid);
}
}
}
/**
* Intercepts {@link DtxResourceManagerEvent}s for {@link DtxResourceManagerState#POST_SYNC_PROCESSING} resource
* managers and executes all registered post-sync jobs for that resource manager.
*
* @param event
* the posted {@link DtxResourceManagerEvent}
*/
@Subscribe
@AllowConcurrentEvents
public final void handleDtxResourceManagerEvent(@Nonnull final DtxResourceManagerEvent event) {
final DtxResourceManagerState newState = event.getNewState();
if (POST_SYNC_PROCESSING != newState) {
// not post-processing, nothing to do here
return;
}
final UUID resId = event.getResourceManagerId();
synchronized (runningPostProcSet) {
runningPostProcSet.add(resId);
}
final DtxManager dtxManager = event.getSource();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Post-synchronization processing starting; node=" + dtxManager.getNodeId() + ", resourceId="
+ resId);
}
final TransactionManager txManager = dtxManager.getTxManager();
if (txManager == null) {
// fail graciously if no transaction manager is available
LOGGER.warn("Transaction manager is null, aborting post-sync processing");
return;
}
final DtxResourceManager targetResMgr = txManager.getRegisteredResourceManager(resId);
if (targetResMgr == null) {
LOGGER.warn("Target resource manager is null, aborting post-sync processing");
return;
}
// attempt to execute the post-sync method
boolean success = true;
try {
targetResMgr.processPostSync();
}
catch (final Throwable e) {
success = false;
}
DtxResourceManagerState targetState = success ? UP_TO_DATE : UNDETERMINED;
synchronized (runningPostProcSet) {
synchronized (resetAfterPostProcSet) {
if (resetAfterPostProcSet.contains(resId)) {
targetState = UNDETERMINED;
resetAfterPostProcSet.remove(resId);
}
}
runningPostProcSet.remove(resId);
}
txManager.setResManagerSyncState(resId, targetState);
}
}