/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.gc; import java.net.URI; import java.util.Iterator; 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.constraint.URIQueryResultList; import com.emc.storageos.db.client.impl.DbClientImpl; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.common.DependencyChecker; import com.emc.storageos.db.common.DependencyTracker; import com.emc.storageos.db.exceptions.DatabaseException; import com.netflix.astyanax.util.TimeUUIDUtils; /** * Runnable implementation for the GC threads */ abstract class GarbageCollectionRunnable implements Runnable { private static final Logger log = LoggerFactory.getLogger(GarbageCollectionRunnable.class); final static String GC_LOCK_PREFIX = "gc/"; final static long MIN_TO_MICROSECS = 60 * 1000 * 1000; final protected Class<? extends DataObject> type; final protected DbClient dbClient; final private long timeStartMarker; final protected DependencyChecker dependencyChecker; final private CoordinatorClient coordinator; GarbageCollectionRunnable(DbClient dbClient, Class<? extends DataObject> type, DependencyTracker dependencyTracker, int gcDelayMins, CoordinatorClient coordinator) { this.type = type; this.dbClient = dbClient; // Now - gcDelay if (gcDelayMins > 0) { timeStartMarker = TimeUUIDUtils.getMicrosTimeFromUUID(TimeUUIDUtils.getUniqueTimeUUIDinMicros()) - (gcDelayMins * MIN_TO_MICROSECS); } else { timeStartMarker = 0; } dependencyChecker = new DependencyChecker(dbClient, dependencyTracker); this.coordinator = coordinator; } /** * Check if a resource could be deleted from DB * * @param id the resource ID * @return true if the resource an be deleted */ protected abstract boolean canBeGC(URI id); /** * get list of uris to check * * @param clazz */ private URIQueryResultList getDecommissionedObjectsOfType(Class<? extends DataObject> clazz) { URIQueryResultList list = new URIQueryResultList(); dbClient.queryInactiveObjects(clazz, timeStartMarker, list); return list; } @Override public void run() { log.info("Starting GC loop: type: {}", type.getSimpleName()); try { URIQueryResultList list = getDecommissionedObjectsOfType(type); int found = 0, deleted = 0; for (Iterator<URI> iterator = list.iterator(); iterator.hasNext();) { URI uri = iterator.next(); found++; log.debug("GC checks dependencies for {}", uri); try { if (!canBeGC(uri)) { continue; } DataObject obj = dbClient.queryObject(type, uri); if (obj != null) { log.info("No dependencies found. Removing {}", uri); ((DbClientImpl)dbClient).internalRemoveObjects(obj); deleted++; } } catch (DatabaseException ex) { log.warn("Exception from database access: ", ex); // To Do - we should skip the whole loop and retry later? } } if (found > 0) { log.info(String.format("Done GC loop: type: %s, processed %s, deleted %s", type.getSimpleName(), found, deleted)); } } catch (Exception e) { log.error("Exception e=", e); } } }