/** @return The interval info map for the aggregator */ protected Map<AggregationInterval, AggregationIntervalInfo> getAggregatorIntervalInfo( final Class<? extends IPortalEventAggregator<?>> aggregatorType) { final AggregatedIntervalConfig aggregatorIntervalConfig = this.intervalsForAggregatorHelper.getAggregatorIntervalConfig(aggregatorType); Map<AggregationInterval, AggregationIntervalInfo> intervalInfo = this.aggregatorReadOnlyIntervalInfo.get(aggregatorType); if (intervalInfo == null) { final Builder<AggregationInterval, AggregationIntervalInfo> intervalInfoBuilder = ImmutableMap.builder(); for (Map.Entry<AggregationInterval, AggregationIntervalInfo> intervalInfoEntry : this.currentIntervalInfo.entrySet()) { final AggregationInterval key = intervalInfoEntry.getKey(); if (aggregatorIntervalConfig.isIncluded(key)) { intervalInfoBuilder.put(key, intervalInfoEntry.getValue()); } } intervalInfo = intervalInfoBuilder.build(); aggregatorReadOnlyIntervalInfo.put(aggregatorType, intervalInfo); } return intervalInfo; }
public IntervalsForAggregatorHelper() { this.defaultAggregatedIntervalConfig = eventAggregationManagementDao.getDefaultAggregatedIntervalConfig(); // Create the set of intervals that are actually being aggregated final Set<AggregationInterval> handledIntervalsNotIncluded = EnumSet.allOf(AggregationInterval.class); final Set<AggregationInterval> handledIntervalsBuilder = EnumSet.noneOf(AggregationInterval.class); for (final IntervalAwarePortalEventAggregator<PortalEvent> portalEventAggregator : intervalAwarePortalEventAggregators) { final Class<? extends IPortalEventAggregator<?>> aggregatorType = PortalRawEventsAggregatorImpl.this.getClass(portalEventAggregator); // Get aggregator specific interval info config final AggregatedIntervalConfig aggregatorIntervalConfig = this.getAggregatorIntervalConfig(aggregatorType); for (final Iterator<AggregationInterval> intervalsIterator = handledIntervalsNotIncluded.iterator(); intervalsIterator.hasNext(); ) { final AggregationInterval interval = intervalsIterator.next(); if (aggregatorIntervalConfig.isIncluded(interval)) { handledIntervalsBuilder.add(interval); intervalsIterator.remove(); } } } handledIntervals = Sets.immutableEnumSet(handledIntervalsBuilder); }
private void doHandleIntervalBoundary( AggregationInterval interval, Map<AggregationInterval, AggregationIntervalInfo> intervals) { for (final IntervalAwarePortalEventAggregator<PortalEvent> portalEventAggregator : intervalAwarePortalEventAggregators) { final Class<? extends IPortalEventAggregator<?>> aggregatorType = PortalRawEventsAggregatorImpl.this.getClass(portalEventAggregator); final AggregatedIntervalConfig aggregatorIntervalConfig = this.intervalsForAggregatorHelper.getAggregatorIntervalConfig(aggregatorType); // If the aggreagator is configured to use the interval notify it of the interval boundary if (aggregatorIntervalConfig.isIncluded(interval)) { final Map<AggregationInterval, AggregationIntervalInfo> aggregatorIntervalInfo = this.getAggregatorIntervalInfo(aggregatorType); portalEventAggregator.handleIntervalBoundary( interval, eventAggregationContext, aggregatorIntervalInfo); } } }
@Override @AggrEventsTransactional public EventProcessingResult doCloseAggregations() { if (!this.clusterLockService.isLockOwner(AGGREGATION_LOCK_NAME)) { throw new IllegalStateException( "The cluster lock " + AGGREGATION_LOCK_NAME + " must be owned by the current thread and server"); } final IEventAggregatorStatus cleanUnclosedStatus = eventAggregationManagementDao.getEventAggregatorStatus(ProcessingType.CLEAN_UNCLOSED, true); // Update status with current server name final String serverName = this.portalInfoProvider.getUniqueServerName(); cleanUnclosedStatus.setServerName(serverName); cleanUnclosedStatus.setLastStart(new DateTime()); // Determine date of most recently aggregated data final IEventAggregatorStatus eventAggregatorStatus = eventAggregationManagementDao.getEventAggregatorStatus(ProcessingType.AGGREGATION, false); if (eventAggregatorStatus == null || eventAggregatorStatus.getLastEventDate() == null) { // Nothing has been aggregated, skip unclosed cleanup cleanUnclosedStatus.setLastEnd(new DateTime()); eventAggregationManagementDao.updateEventAggregatorStatus(cleanUnclosedStatus); return new EventProcessingResult(0, null, null, true); } final DateTime lastAggregatedDate = eventAggregatorStatus.getLastEventDate(); // If lastCleanUnclosedDate is null use the oldest date dimension as there can be // no aggregations that exist before it final DateTime lastCleanUnclosedDate; if (cleanUnclosedStatus.getLastEventDate() == null) { final DateDimension oldestDateDimension = this.dateDimensionDao.getOldestDateDimension(); lastCleanUnclosedDate = oldestDateDimension.getDate().toDateTime(); } else { lastCleanUnclosedDate = cleanUnclosedStatus.getLastEventDate(); } if (!(lastCleanUnclosedDate.isBefore(lastAggregatedDate))) { logger.debug( "No events aggregated since last unclosed aggregation cleaning, skipping clean: {}", lastAggregatedDate); return new EventProcessingResult(0, lastCleanUnclosedDate, lastAggregatedDate, true); } // Switch to flush on commit to avoid flushes during queries final EntityManager entityManager = this.getEntityManager(); entityManager.flush(); entityManager.setFlushMode(FlushModeType.COMMIT); // Track the number of closed aggregations and the last date of a cleaned interval int closedAggregations = 0; int cleanedIntervals = 0; DateTime cleanUnclosedEnd; final Thread currentThread = Thread.currentThread(); final String currentName = currentThread.getName(); try { currentThread.setName(currentName + "-" + lastCleanUnclosedDate + "-" + lastAggregatedDate); // Local caches used to reduce db io final IntervalsForAggregatorHelper intervalsForAggregatorHelper = new IntervalsForAggregatorHelper(); final Map<AggregationInterval, AggregationIntervalInfo> previousIntervals = new HashMap<AggregationInterval, AggregationIntervalInfo>(); // A DateTime within the next interval to close aggregations in DateTime nextIntervalDate = lastCleanUnclosedDate; do { // Reset our goal of catching up to the last aggregated event on every iteration cleanUnclosedEnd = lastAggregatedDate; // For each interval the aggregator supports, cleanup the unclosed aggregations for (final AggregationInterval interval : intervalsForAggregatorHelper.getHandledIntervals()) { final AggregationIntervalInfo previousInterval = previousIntervals.get(interval); if (previousInterval != null && nextIntervalDate.isBefore(previousInterval.getEnd())) { logger.debug( "{} interval before {} has already been cleaned during this execution, ignoring", interval, previousInterval.getEnd()); continue; } // The END date of the last clean session will find us the next interval to clean final AggregationIntervalInfo nextIntervalToClean = intervalHelper.getIntervalInfo(interval, nextIntervalDate); previousIntervals.put(interval, nextIntervalToClean); if (nextIntervalToClean == null) { continue; } final DateTime start = nextIntervalToClean.getStart(); final DateTime end = nextIntervalToClean.getEnd(); if (!end.isBefore(lastAggregatedDate)) { logger.debug( "{} interval between {} and {} is still active, ignoring", new Object[] {interval, start, end}); continue; } // Track the oldest interval end, this ensures that nothing is missed if (end.isBefore(cleanUnclosedEnd)) { cleanUnclosedEnd = end; } logger.debug( "Cleaning unclosed {} aggregations between {} and {}", new Object[] {interval, start, end}); for (final IntervalAwarePortalEventAggregator<PortalEvent> portalEventAggregator : intervalAwarePortalEventAggregators) { checkShutdown(); final Class<? extends IPortalEventAggregator<?>> aggregatorType = getClass(portalEventAggregator); // Get aggregator specific interval info config final AggregatedIntervalConfig aggregatorIntervalConfig = intervalsForAggregatorHelper.getAggregatorIntervalConfig(aggregatorType); // If the aggregator is being used for the specified interval call // cleanUnclosedAggregations if (aggregatorIntervalConfig.isIncluded(interval)) { closedAggregations += portalEventAggregator.cleanUnclosedAggregations(start, end, interval); } } cleanedIntervals++; } // Set the next interval to the end date from the last aggregation run nextIntervalDate = cleanUnclosedEnd; logger.debug( "Closed {} aggregations across {} interval before {} with goal of {}", new Object[] { closedAggregations, cleanedIntervals, cleanUnclosedEnd, lastAggregatedDate }); // Loop until either the batchSize of cleaned aggregations has been reached or no // aggregation work is done } while (closedAggregations <= cleanUnclosedAggregationsBatchSize && cleanedIntervals <= cleanUnclosedIntervalsBatchSize && cleanUnclosedEnd.isBefore(lastAggregatedDate)); } finally { currentThread.setName(currentName); } // Update the status object and store it cleanUnclosedStatus.setLastEventDate(cleanUnclosedEnd); cleanUnclosedStatus.setLastEnd(new DateTime()); eventAggregationManagementDao.updateEventAggregatorStatus(cleanUnclosedStatus); return new EventProcessingResult( closedAggregations, lastCleanUnclosedDate, lastAggregatedDate, !cleanUnclosedEnd.isBefore(lastAggregatedDate)); }