/* * Copyright (c) 2017 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.client.upgrade.callbacks; import java.io.File; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.impl.DataObjectType; import com.emc.storageos.db.client.impl.DbCheckerFileWriter; import com.emc.storageos.db.client.impl.DbClientContext; import com.emc.storageos.db.client.impl.DbClientImpl; import com.emc.storageos.db.client.impl.DbConsistencyCheckerHelper; import com.emc.storageos.db.client.impl.DbConsistencyCheckerHelper.CheckResult; import com.emc.storageos.db.client.impl.DbConsistencyCheckerHelper.IndexAndCf; import com.emc.storageos.db.client.impl.TypeMap; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.db.client.util.KeyspaceUtil; import com.emc.storageos.services.util.Exec; import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException; import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; /** * This migration handler is for COP-27665 * If we see an object URI in index table but never see it in object table, * it's definitely a potential problem for NullPointerException. * So, create a new migration callback. Scan all index tables including DecommissionIndex, * AggregatedIndex, RelationIndex etc, and delete invalid object URI */ public class StaleIndexCleanerMigration extends BaseCustomMigrationCallback { private static final Logger log = LoggerFactory.getLogger(StaleIndexCleanerMigration.class); private static final String CLEANUP_COMMAND = "/opt/storageos/bin/cqlsh -k %s -f %s localhost %s"; private DbConsistencyCheckerHelper checkHelper; @Override public void process() throws MigrationCallbackException { checkHelper = new DbConsistencyCheckerHelper((DbClientImpl)getDbClient()); checkHelper.setDoubleConfirmed(false); Map<String, IndexAndCf> allIdxCfs = getAllIndexCFs(); CheckResult checkResult = new CheckResult(); try { for (IndexAndCf indexAndCf : allIdxCfs.values()) { try { checkHelper.checkIndexingCF(indexAndCf, false, checkResult, true); } catch (ConnectionException e) { log.error("Failed to check stale index CF {}", indexAndCf, e); } } ThreadPoolExecutor executor = checkHelper.getExecutor(); executor.shutdown(); try { if (!executor.awaitTermination(120, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (Exception e) { executor.shutdownNow(); } log.info("Totally find {} stale index", checkResult.getTotal()); if (checkResult.getTotal() > 0) { executeCleanupScripts(); } } catch (Exception e) { log.error("failed to cleanup stale/invalid index:", e); } finally { DbCheckerFileWriter.close(); } } private void executeCleanupScripts() { for (Entry<String, String> entry : DbCheckerFileWriter.getCleanupfileMap().entrySet()) { if (DbCheckerFileWriter.WriteType.STORAGEOS.name().equalsIgnoreCase(entry.getKey())) { execCleanupScript(String.format(CLEANUP_COMMAND, DbClientContext.LOCAL_KEYSPACE_NAME, entry.getValue(), DbClientContext.DB_THRIFT_PORT)); FileUtils.deleteQuietly(new File(entry.getValue())); } } } private Map<String, IndexAndCf> getAllIndexCFs() { Map<String, IndexAndCf> allIdxCfs = new TreeMap<>(); for (DataObjectType objType : TypeMap.getAllDoTypes()) { if (KeyspaceUtil.isLocal(objType.getDataObjectClass())) { Map<String, IndexAndCf> idxCfs = checkHelper.getIndicesOfCF(objType); allIdxCfs.putAll(idxCfs); } } return allIdxCfs; } public void execCleanupScript(String command) { Exec.Result result = Exec.exec(Exec.DEFAULT_CMD_TIMEOUT, command.split(" ")); log.info("External command result: {}", result); } }