/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.client.upgrade.callbacks; import com.emc.storageos.db.client.impl.DataObjectType; import com.emc.storageos.db.client.impl.TypeMap; import com.emc.storageos.db.client.impl.ColumnField; import com.emc.storageos.db.client.impl.DbIndex; import com.emc.storageos.db.client.impl.AggregateDbIndex; import com.emc.storageos.db.client.upgrade.InternalDbClient; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.services.util.AlertsLogger; import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Map; import java.util.HashMap; /** * Migration for the Aggregation Index fields. * They are not going to use TimeUUID to enforce consistency. * Consistency is not enforced anyway. But UUID causes extraneous tombstones in the database. */ public class AggregationIndexTimeUUIDMigration extends BaseCustomMigrationCallback { private static final Logger log = LoggerFactory.getLogger(AggregationIndexTimeUUIDMigration.class); private AlertsLogger alertLog = AlertsLogger.getAlertsLogger(); @Override public void process() throws MigrationCallbackException { log.info("Starting aggregation index processing"); boolean success = true; try { removeOldAggregationIndex(); log.info("Removed old aggregation index"); removeTimeUUIDIndexedFields(Volume.class); } catch (Exception e) { success = false; } try { log.info("Rebuilt aggregated fields for CF Volume"); removeTimeUUIDIndexedFields(FileShare.class); } catch (Exception e) { success = false; } try { log.info("Rebuilt aggregated fields for CF FileShare"); removeTimeUUIDIndexedFields(StoragePool.class); log.info("Rebuilt aggregated fields for CF StoragePool"); } catch (Exception e) { success = false; } if (success == false) { String errMsg = String.format("The DB migration callback %s is completed, but leaves some corrupted rows unprocessed, " + "See the dbsvc.log/geodbsvc.log for more detailed information. Please open an EMC support request for this issue", this.getClass().getSimpleName()); alertLog.error(errMsg); } } private void removeOldAggregationIndex() { InternalDbClient internalDbClient = getInternalDbClient(); internalDbClient.rebuildCf("AggregatedIndex"); } private void removeTimeUUIDIndexedFields(Class<? extends DataObject> clazz) throws Exception { DataObjectType doType = TypeMap.getDoType(clazz); Collection<ColumnField> fields = doType.getColumnFields(); Map<String, ColumnField> uuidFields = new HashMap<>(); for (ColumnField field : fields) { DbIndex index = field.getIndex(); if (index != null && index instanceof AggregateDbIndex) { uuidFields.put(field.getName(), field); } } getInternalDbClient().resetFields(clazz, uuidFields, true); // true: ignore exception while accessing db } private InternalDbClient getInternalDbClient() { if (InternalDbClient.class.isAssignableFrom(dbClient.getClass())) { return (InternalDbClient) dbClient; } else { throw new IllegalStateException("Migration callback " + name + " needs InternalDbClient"); } } }