/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.server.impl; import com.emc.storageos.coordinator.client.model.CoordinatorClassInfo; import com.emc.storageos.coordinator.client.model.CoordinatorSerializable; import com.emc.storageos.coordinator.exceptions.CoordinatorException; import com.emc.storageos.coordinator.exceptions.FatalCoordinatorException; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; public class DbRepairJobState implements CoordinatorSerializable { private static final Logger log = LoggerFactory.getLogger(DbRepairJobState.class); private static final ObjectMapper mapper = new ObjectMapper().enableDefaultTyping(); private String lastSuccessDigest; private Boolean lastCrossVdc; private Long lastSuccessStartTime; private Long lastSuccessEndTime; private String currentDigest; private String currentWorker; // For debugging so we know which node is driving repair private Long currentStartTime; private Long currentUpdateTime; private String currentToken; private Integer currentProgress; private Integer currentRetry; private Boolean currentCrossVdc; public DbRepairJobState() { } public DbRepairJobState(String clusterDigest) { this.currentRetry = 0; this.currentProgress = 0; this.currentDigest = clusterDigest; this.currentStartTime = System.currentTimeMillis(); this.currentUpdateTime = System.currentTimeMillis(); } @Override public String toString() { try { return mapper.writeValueAsString(this); } catch (IOException e) { log.error("Failed to serialize this object", e); return null; } } public String getLastSuccessDigest() { return lastSuccessDigest; } public void setLastSuccessDigest(String lastSuccessDigest) { this.lastSuccessDigest = lastSuccessDigest; } public Boolean getLastCrossVdc() { return lastCrossVdc; } public void setLastCrossVdc(Boolean lastCrossVdc) { this.lastCrossVdc = lastCrossVdc; } public Long getLastSuccessStartTime() { return lastSuccessStartTime; } public void setLastSuccessStartTime(Long lastSuccessStartTime) { this.lastSuccessStartTime = lastSuccessStartTime; } public Long getLastSuccessEndTime() { return lastSuccessEndTime; } public void setLastSuccessEndTime(Long lastSuccessEndTime) { this.lastSuccessEndTime = lastSuccessEndTime; } public String getCurrentDigest() { return currentDigest; } public void setCurrentDigest(String currentDigest) { this.currentDigest = currentDigest; } public String getCurrentWorker() { return currentWorker; } public void setCurrentWorker(String currentWorker) { this.currentWorker = currentWorker; } public Long getCurrentStartTime() { return currentStartTime; } public void setCurrentStartTime(Long currentStartTime) { this.currentStartTime = currentStartTime; } public Long getCurrentUpdateTime() { return currentUpdateTime; } public void setCurrentUpdateTime(Long currentUpdateTime) { this.currentUpdateTime = currentUpdateTime; } public String getCurrentToken() { return currentToken; } public void setCurrentToken(String currentToken) { this.currentToken = currentToken; } public Integer getCurrentProgress() { return currentProgress; } public void setCurrentProgress(Integer currentProgress) { this.currentProgress = currentProgress; } public Integer getCurrentRetry() { return currentRetry; } public void setCurrentRetry(Integer currentRetry) { this.currentRetry = currentRetry; } @Deprecated public Boolean getCurrentCrossVdc() { return currentCrossVdc; } @Deprecated public void setCurrentCrossVdc(Boolean currentCrossVdc) { this.currentCrossVdc = currentCrossVdc; } @Override public String encodeAsString() { return toString(); } @Override public DbRepairJobState decodeFromString(String infoStr) throws FatalCoordinatorException { try { mapper.readerForUpdating(this).readValue(infoStr); return this; } catch (IOException e) { log.error("Failed to decode data string", e); throw CoordinatorException.fatals.decodingError(e.getMessage()); } } @Override @JsonIgnore public CoordinatorClassInfo getCoordinatorClassInfo() { return null; } // See if we can resume: there's is something to resume, and the retry time is not reaching limit, and is in compatible config @JsonIgnore public boolean canResume(String clusterDigest, int maxRetryTimes) { return this.currentToken != null && this.currentRetry < maxRetryTimes && this.currentDigest.equals(clusterDigest); } @JsonIgnore private boolean isIntervalElapse() { long now = System.currentTimeMillis(); return (this.lastSuccessEndTime + DbRepairRunnable.INTERVAL_TIME_IN_MINUTES * 60 * 1000 < now); } @JsonIgnore public boolean notSuitableForNewRepair(String clusterDigest) { return this.lastSuccessEndTime != null && this.lastSuccessDigest.equals(clusterDigest) && !isIntervalElapse(); } @JsonIgnore public void increaseRetry() { this.currentRetry++; } @JsonIgnore public void updateProgress(int progress, String currentToken) { this.currentProgress = progress; this.currentToken = currentToken; } @JsonIgnore public boolean success(String clusterDigest) { if (!clusterDigest.equals(this.currentDigest)) { return false; } this.lastSuccessDigest = this.getCurrentDigest(); this.lastSuccessStartTime = this.getCurrentStartTime(); this.lastSuccessEndTime = System.currentTimeMillis(); cleanCurrentFields(); return true; } @JsonIgnore public void cleanCurrentFields() { this.currentToken = null; this.currentProgress = null; this.currentRetry = null; this.currentDigest = null; this.currentWorker = null; this.currentStartTime = null; this.currentCrossVdc = null; } @JsonIgnore public boolean retry(int maxRetryTimes) { this.increaseRetry(); if (this.getCurrentRetry() > maxRetryTimes) { log.error("Current db repair retry number({}) exceed the limit({})", this.getCurrentRetry(), maxRetryTimes); return false; } return true; } @JsonIgnore public void fail(int maxRetryTimes) { if (this.getCurrentRetry() <= maxRetryTimes) { this.increaseRetry(); } } @JsonIgnore public void inProgress(String clusterDigest) { this.currentRetry = 0; this.currentProgress = 0; this.currentDigest = clusterDigest; this.currentStartTime = System.currentTimeMillis(); this.currentUpdateTime = System.currentTimeMillis(); } }