package com.hubspot.singularity.data.history; import java.util.Date; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.codahale.metrics.annotation.Timed; import com.google.common.base.Optional; import com.google.inject.Inject; import com.hubspot.singularity.DeployState; import com.hubspot.singularity.ExtendedTaskState; import com.hubspot.singularity.OrderDirection; import com.hubspot.singularity.SingularityDeployHistory; import com.hubspot.singularity.SingularityRequest; import com.hubspot.singularity.SingularityRequestHistory; import com.hubspot.singularity.SingularityTaskHistory; import com.hubspot.singularity.SingularityTaskIdHistory; import com.hubspot.singularity.data.history.SingularityMappers.SingularityRequestIdCount; import com.hubspot.singularity.data.transcoders.Transcoder; public class JDBIHistoryManager implements HistoryManager { private static final Logger LOG = LoggerFactory.getLogger(JDBIHistoryManager.class); private final HistoryJDBI history; private final Transcoder<SingularityTaskHistory> taskHistoryTranscoder; private final Transcoder<SingularityDeployHistory> deployHistoryTranscoder; private final Transcoder<SingularityRequest> singularityRequestTranscoder; @Inject public JDBIHistoryManager(HistoryJDBI history, Transcoder<SingularityTaskHistory> taskHistoryTranscoder, Transcoder<SingularityDeployHistory> deployHistoryTranscoder, Transcoder<SingularityRequest> singularityRequestTranscoder) { this.taskHistoryTranscoder = taskHistoryTranscoder; this.deployHistoryTranscoder = deployHistoryTranscoder; this.singularityRequestTranscoder = singularityRequestTranscoder; this.history = history; } @Override @Timed public List<SingularityTaskIdHistory> getTaskIdHistory(Optional<String> requestId, Optional<String> deployId, Optional<String> runId, Optional<String> host, Optional<ExtendedTaskState> lastTaskStatus, Optional<Long> startedBefore, Optional<Long> startedAfter, Optional<Long> updatedBefore, Optional<Long> updatedAfter, Optional<OrderDirection> orderDirection, Optional<Integer> limitStart, Integer limitCount) { return history.getTaskIdHistory(requestId, deployId, runId, host, lastTaskStatus, startedBefore, startedAfter, updatedBefore, updatedAfter, orderDirection, limitStart, limitCount); } @Override @Timed public int getTaskIdHistoryCount(Optional<String> requestId, Optional<String> deployId, Optional<String> runId, Optional<String> host, Optional<ExtendedTaskState> lastTaskStatus, Optional<Long> startedBefore, Optional<Long> startedAfter, Optional<Long> updatedBefore, Optional<Long> updatedAfter) { return history.getTaskIdHistoryCount(requestId, deployId, runId, host, lastTaskStatus, startedBefore, startedAfter, updatedBefore, updatedAfter); } private String getVarcharField(Optional<String> field, int maxLength) { if (!field.isPresent()) { return null; } if (field.get().length() > maxLength) { return field.get().substring(0, maxLength); } return field.get(); } private String getMessageField(Optional<String> message) { return getVarcharField(message, 280); } private String getUserField(Optional<String> user) { return getVarcharField(user, 100); } @Override public void saveRequestHistoryUpdate(SingularityRequestHistory requestHistory) { history.insertRequestHistory(requestHistory.getRequest().getId(), singularityRequestTranscoder.toBytes(requestHistory.getRequest()), new Date(requestHistory.getCreatedAt()), requestHistory.getEventType().name(), getUserField(requestHistory.getUser()), getMessageField(requestHistory.getMessage())); } @Override public void saveDeployHistory(SingularityDeployHistory deployHistory) { history.insertDeployHistory(deployHistory.getDeployMarker().getRequestId(), deployHistory.getDeployMarker().getDeployId(), new Date(deployHistory.getDeployMarker().getTimestamp()), getUserField(deployHistory.getDeployMarker().getUser()), getMessageField(deployHistory.getDeployMarker().getMessage()), deployHistory.getDeployResult().isPresent() ? new Date(deployHistory.getDeployResult().get().getTimestamp()) : new Date(deployHistory.getDeployMarker().getTimestamp()), deployHistory.getDeployResult().isPresent() ? deployHistory.getDeployResult().get().getDeployState().name() : DeployState.CANCELED.name(), deployHistoryTranscoder.toBytes(deployHistory)); } @Override public Optional<SingularityDeployHistory> getDeployHistory(String requestId, String deployId) { byte[] historyBytes = history.getDeployHistoryForDeploy(requestId, deployId); if (historyBytes == null) { return Optional.absent(); } return Optional.of(deployHistoryTranscoder.fromBytes(historyBytes)); } @Override public List<SingularityDeployHistory> getDeployHistoryForRequest(String requestId, Integer limitStart, Integer limitCount) { return history.getDeployHistoryForRequest(requestId, limitStart, limitCount); } @Override public int getDeployHistoryForRequestCount(String requestId) { return history.getDeployHistoryForRequestCount(requestId); } private String getOrderDirection(Optional<OrderDirection> orderDirection) { return orderDirection.or(OrderDirection.DESC).name(); } @Override public List<SingularityRequestHistory> getRequestHistory(String requestId, Optional<OrderDirection> orderDirection, Integer limitStart, Integer limitCount) { return history.getRequestHistory(requestId, getOrderDirection(orderDirection), limitStart, limitCount); } @Override public int getRequestHistoryCount(String requestId) { return history.getRequestHistoryCount(requestId); } @Override public List<String> getRequestHistoryLike(String requestIdLike, Integer limitStart, Integer limitCount) { return history.getRequestHistoryLike(requestIdLike, limitStart, limitCount); } @Override public void saveTaskHistory(SingularityTaskHistory taskHistory) { if (history.getTaskHistoryForTask(taskHistory.getTask().getTaskId().getId()) != null) { return; } SingularityTaskIdHistory taskIdHistory = SingularityTaskIdHistory.fromTaskIdAndTaskAndUpdates(taskHistory.getTask().getTaskId(), taskHistory.getTask(), taskHistory.getTaskUpdates()); String lastTaskStatus = null; if (taskIdHistory.getLastTaskState().isPresent()) { lastTaskStatus = taskIdHistory.getLastTaskState().get().name(); } history.insertTaskHistory(taskIdHistory.getTaskId().getRequestId(), taskIdHistory.getTaskId().getId(), taskHistoryTranscoder.toBytes(taskHistory), new Date(taskIdHistory.getUpdatedAt()), lastTaskStatus, taskHistory.getTask().getTaskRequest().getPendingTask().getRunId().orNull(), taskIdHistory.getTaskId().getDeployId(), taskIdHistory.getTaskId().getHost(), new Date(taskIdHistory.getTaskId().getStartedAt())); } @Override public Optional<SingularityTaskHistory> getTaskHistory(String taskId) { byte[] historyBytes = history.getTaskHistoryForTask(taskId); if (historyBytes == null || historyBytes.length == 0) { return Optional.absent(); } return Optional.of(taskHistoryTranscoder.fromBytes(historyBytes)); } @Override public Optional<SingularityTaskHistory> getTaskHistoryByRunId(String requestId, String runId) { byte[] historyBytes = history.getTaskHistoryForTaskByRunId(requestId, runId); if (historyBytes == null || historyBytes.length == 0) { return Optional.absent(); } return Optional.of(taskHistoryTranscoder.fromBytes(historyBytes)); } @Override public List<SingularityRequestIdCount> getRequestIdCounts(Date before) { return history.getRequestIdCounts(before); } @Override public List<String> getRequestIdsInTaskHistory() { return history.getRequestIdsInTaskHistory(); } @Override public int getUnpurgedTaskHistoryCountByRequestBefore(String requestId, Date before) { return history.getUnpurgedTaskHistoryCountByRequestBefore(requestId, before); } @Override public void purgeTaskHistory(String requestId, int count, Optional<Integer> limit, Optional<Date> purgeBefore, boolean deleteRowInsteadOfUpdate, Integer maxPurgeCount) { if (limit.isPresent() && count > limit.get()) { Date beforeBasedOnLimit = history.getMinUpdatedAtWithLimitForRequest(requestId, limit.get()); if (deleteRowInsteadOfUpdate) { LOG.debug("Deleting task history for {} above {} items (before {})", requestId, limit.get(), beforeBasedOnLimit); history.deleteTaskHistoryForRequestBefore(requestId, beforeBasedOnLimit, maxPurgeCount); } else { LOG.debug("Purging task history bytes for {} above {} items (before {})", requestId, limit.get(), beforeBasedOnLimit); history.updateTaskHistoryNullBytesForRequestBefore(requestId, beforeBasedOnLimit, maxPurgeCount); } } if (purgeBefore.isPresent()) { if (deleteRowInsteadOfUpdate) { LOG.debug("Deleting task history for {} before {}", requestId, purgeBefore.get()); history.deleteTaskHistoryForRequestBefore(requestId, purgeBefore.get(), maxPurgeCount); } else { LOG.debug("Purging task history bytes for {} before {}", requestId, purgeBefore.get()); history.updateTaskHistoryNullBytesForRequestBefore(requestId, purgeBefore.get(), maxPurgeCount); } } } }