/** * Licensed to JumpMind Inc under one or more contributor * license agreements. See the NOTICE file distributed * with this work for additional information regarding * copyright ownership. JumpMind Inc licenses this file * to you under the GNU General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * <http://www.gnu.org/licenses/>. * * 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 org.jumpmind.symmetric.route; import static org.apache.commons.lang.StringUtils.isNotBlank; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.jumpmind.db.sql.ISqlTransaction; import org.jumpmind.db.sql.SqlException; import org.jumpmind.symmetric.SymmetricException; import org.jumpmind.symmetric.model.Data; import org.jumpmind.symmetric.model.DataEvent; import org.jumpmind.symmetric.model.DataGap; import org.jumpmind.symmetric.model.Node; import org.jumpmind.symmetric.model.NodeChannel; import org.jumpmind.symmetric.model.OutgoingBatch; import org.jumpmind.symmetric.model.TriggerRouter; import org.slf4j.Logger; public class ChannelRouterContext extends SimpleRouterContext { public static final String STAT_INSERT_DATA_EVENTS_MS = "data.events.insert.time.ms"; public static final String STAT_DATA_ROUTER_MS = "data.router.time.ms"; public static final String STAT_QUERY_TIME_MS = "data.read.query.time.ms"; public static final String STAT_READ_DATA_MS = "data.read.total.time.ms"; public static final String STAT_REREAD_DATA_MS = "data.reread.time.ms"; public static final String STAT_ENQUEUE_DATA_MS = "data.enqueue.time.ms"; public static final String STAT_ENQUEUE_EOD_MS = "data.enqueue.eod.time.ms"; public static final String STAT_DATA_EVENTS_INSERTED = "data.events.insert.count"; public static final String STAT_DATA_ROUTED_COUNT = "data.routed.count"; public static final String STAT_ROUTE_TOTAL_TIME = "total.time.ms"; private Map<String, OutgoingBatch> batchesByNodes = new HashMap<String, OutgoingBatch>(); private Map<TriggerRouter, Set<Node>> availableNodes = new HashMap<TriggerRouter, Set<Node>>(); private Set<IDataRouter> usedDataRouters = new HashSet<IDataRouter>(); private ISqlTransaction sqlTransaction; private boolean needsCommitted = false; private long createdTimeInMs = System.currentTimeMillis(); private Data lastDataProcessed; private List<DataEvent> dataEventsToSend = new ArrayList<DataEvent>(); private boolean produceCommonBatches = false; private boolean onlyDefaultRoutersAssigned = false; private long lastLoadId = -1; private long startDataId; private long endDataId; private long dataReadCount; private long peekAheadFillCount; private long maxPeekAheadQueueSize; private List<DataGap> dataGaps = new ArrayList<DataGap>(); private Set<String> transactions = new HashSet<String>(); public ChannelRouterContext(String nodeId, NodeChannel channel, ISqlTransaction transaction) throws SQLException { super(nodeId, channel); this.sqlTransaction = transaction; this.sqlTransaction.setInBatchMode(true); } public List<DataEvent> getDataEventList() { return dataEventsToSend; } public void clearDataEventsList() { dataEventsToSend.clear(); } public void addDataEvent(long dataId, long batchId, String routerId) { dataEventsToSend.add(new DataEvent(dataId, batchId, routerId)); } public Map<String, OutgoingBatch> getBatchesByNodes() { return batchesByNodes; } public Map<TriggerRouter, Set<Node>> getAvailableNodes() { return availableNodes; } public void commit() { try { sqlTransaction.commit(); } finally { clearState(); } } protected void clearState() { this.usedDataRouters.clear(); this.encountedTransactionBoundary = false; this.requestGapDetection = false; this.batchesByNodes.clear(); this.availableNodes.clear(); this.dataEventsToSend.clear(); } public void rollback() { try { sqlTransaction.rollback(); } catch (SqlException e) { log.warn("Rollback attempt failed", e); } finally { clearState(); } } public void cleanup() { try { this.sqlTransaction.commit(); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new SymmetricException(ex); } finally { this.sqlTransaction.close(); } } @Override synchronized public void logStats(Logger log, long totalTimeInMs) { super.logStats(log, totalTimeInMs); if (log.isDebugEnabled()) { log.debug(channel.getChannelId() + ", startDataId=" + startDataId + ", endDataId=" + endDataId + ", dataReadCount=" + dataReadCount + ", peekAheadFillCount=" + peekAheadFillCount + ", transactions=" + transactions.toString() + ", dataGaps=" + dataGaps.toString()); } } public void setNeedsCommitted(boolean b) { this.needsCommitted = b; } public boolean isNeedsCommitted() { return needsCommitted; } public Set<IDataRouter> getUsedDataRouters() { return usedDataRouters; } public void addUsedDataRouter(IDataRouter dataRouter) { this.usedDataRouters.add(dataRouter); } public void resetForNextData() { this.needsCommitted = false; } public long getCreatedTimeInMs() { return createdTimeInMs; } public void setLastDataProcessed(Data lastDataProcessed) { this.lastDataProcessed = lastDataProcessed; } public Data getLastDataProcessed() { return lastDataProcessed; } public ISqlTransaction getSqlTransaction() { return sqlTransaction; } public void setProduceCommonBatches(boolean defaultRoutersOnly) { this.produceCommonBatches = defaultRoutersOnly; } public boolean isProduceCommonBatches() { return produceCommonBatches; } public void setLastLoadId(long lastLoadId) { this.lastLoadId = lastLoadId; } public long getLastLoadId() { return lastLoadId; } public long getStartDataId() { return startDataId; } public void setStartDataId(long startDataId) { this.startDataId = startDataId; } public long getEndDataId() { return endDataId; } public void setEndDataId(long endDataId) { this.endDataId = endDataId; } public long getDataReadCount() { return dataReadCount; } public void incrementDataReadCount(long dataReadCount) { this.dataReadCount += dataReadCount; } public long getPeekAheadFillCount() { return peekAheadFillCount; } public long getMaxPeekAheadQueueSize() { return maxPeekAheadQueueSize; } public void setMaxPeekAheadQueueSize(long maxPeekAheadQueueSize) { this.maxPeekAheadQueueSize = maxPeekAheadQueueSize; } public void incrementPeekAheadFillCount(long peekAheadFillCount) { this.peekAheadFillCount += peekAheadFillCount; } public List<DataGap> getDataGaps() { return dataGaps; } public void setDataGaps(List<DataGap> dataGaps) { this.dataGaps = dataGaps; } public Set<String> getTransactions() { return transactions; } public void addTransaction(String transactionId) { if (isNotBlank(transactionId)) { this.transactions.add(transactionId); } } public void setOnlyDefaultRoutersAssigned(boolean onlyDefaultRoutersAssigned) { this.onlyDefaultRoutersAssigned = onlyDefaultRoutersAssigned; } public boolean isOnlyDefaultRoutersAssigned() { return onlyDefaultRoutersAssigned; } }