/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.event; import java.net.URI; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.ActionableEvent; import com.emc.storageos.services.util.NamedScheduledThreadPoolExecutor; import com.google.common.collect.Lists; import com.netflix.astyanax.util.TimeUUIDUtils; /** * Deletes events that are over {@link #EVENT_TTL_MINS_PROPERTY} old at periodic intervals */ public class ActionableEventScrubberExecutor { private static final Logger log = LoggerFactory.getLogger(ActionableEventScrubberExecutor.class); private static final String EVENT_TTL_MINS_PROPERTY = "event_ttl"; private static final String EVENT_CLEAN_INTERVAL_PROPERTY = "event_clean_interval"; private final static long MIN_TO_MICROSECS = 60 * 1000 * 1000; private final static long MINI_TO_MICROSECS = 1000; private final static long MINIMUM_PERIOD_MINS = 60; private final static int DELETE_BATCH_SIZE = 100; private ScheduledExecutorService _executor = new NamedScheduledThreadPoolExecutor("ActionableEventScrubber", 1); private DbClient dbClient; private CoordinatorClient coordinator; public void start() { _executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { deleteOldEvents(); } }, 1, getConfigProperty(EVENT_CLEAN_INTERVAL_PROPERTY, MINIMUM_PERIOD_MINS), TimeUnit.MINUTES); log.info("Started Actionable Event Scrubber"); } public DbClient getDbClient() { return dbClient; } public void setDbClient(DbClient dbClient) { this.dbClient = dbClient; } public CoordinatorClient getCoordinator() { return coordinator; } public void setCoordinator(CoordinatorClient coordinator) { this.coordinator = coordinator; } private void deleteOldEvents() { log.info("Looking for completed events older than {} minutes", getConfigProperty(EVENT_TTL_MINS_PROPERTY, MINIMUM_PERIOD_MINS)); long eventLifetimeMicroSeconds = getConfigProperty(EVENT_TTL_MINS_PROPERTY, MINIMUM_PERIOD_MINS) * MIN_TO_MICROSECS; long currentTimeMicroseconds = TimeUUIDUtils.getMicrosTimeFromUUID(TimeUUIDUtils.getUniqueTimeUUIDinMicros()); long startTimeMicroSec = currentTimeMicroseconds - eventLifetimeMicroSeconds; Calendar startTimeMarker = Calendar.getInstance(); startTimeMarker.setTimeInMillis(startTimeMicroSec / MINI_TO_MICROSECS); List<URI> ids = dbClient.queryByType(ActionableEvent.class, true); Iterator<ActionableEvent> events = dbClient.queryIterativeObjects(ActionableEvent.class, ids, true); List<ActionableEvent> toBeDeleted = Lists.newArrayList(); while (events.hasNext()) { ActionableEvent event = events.next(); if (event.getCreationTime().after(startTimeMarker)) { continue; } if (event != null && !ActionableEvent.Status.pending.name().equalsIgnoreCase(event.getEventStatus()) && !ActionableEvent.Status.failed.name().equalsIgnoreCase(event.getEventStatus())) { toBeDeleted.add(event); } if (toBeDeleted.size() >= DELETE_BATCH_SIZE) { log.info("Deleting {} Actionable Events", toBeDeleted.size()); dbClient.markForDeletion(toBeDeleted); toBeDeleted.clear(); } } if (!toBeDeleted.isEmpty()) { log.info("Deleting {} Actionable Events", toBeDeleted.size()); dbClient.markForDeletion(toBeDeleted); } log.info("delete completed actionable events successfully"); } private long getConfigProperty(String propertyName, long minimumValue) { String value = coordinator.getPropertyInfo().getProperty(propertyName); if (value != null && StringUtils.isNotBlank(value)) { try { return Math.max(Long.valueOf(value), minimumValue); } catch (Exception e) { log.error("Configuration property " + propertyName + " invalid number, using minimum value of " + minimumValue, e); return minimumValue; } } else { log.error("Configuration property " + propertyName + " not found, using minimum value of " + minimumValue); return minimumValue; } } }