com.teradata.benchto.service.BenchmarkService.java Source code

Java tutorial

Introduction

Here is the source code for com.teradata.benchto.service.BenchmarkService.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.teradata.benchto.service;

import com.teradata.benchto.service.model.AggregatedMeasurement;
import com.teradata.benchto.service.model.BenchmarkRun;
import com.teradata.benchto.service.model.BenchmarkRunExecution;
import com.teradata.benchto.service.model.Environment;
import com.teradata.benchto.service.model.Measurement;
import com.teradata.benchto.service.model.Status;
import com.teradata.benchto.service.repo.BenchmarkRunRepo;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.TransientDataAccessException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.teradata.benchto.service.model.Environment.DEFAULT_ENVIRONMENT_NAME;
import static com.teradata.benchto.service.model.Status.STARTED;
import static com.teradata.benchto.service.utils.BenchmarkUniqueNameUtils.generateBenchmarkUniqueName;
import static com.teradata.benchto.service.utils.TimeUtils.currentDateTime;

@Service
public class BenchmarkService {
    private static final Logger LOG = LoggerFactory.getLogger(BenchmarkService.class);

    @Autowired
    private BenchmarkRunRepo benchmarkRunRepo;

    @Autowired
    private EnvironmentService environmentService;

    @Retryable(value = { TransientDataAccessException.class, DataIntegrityViolationException.class })
    @Transactional
    public String startBenchmarkRun(String uniqueName, String name, String sequenceId,
            Optional<String> environmentName, Map<String, String> variables, Map<String, String> attributes) {
        String generatedUniqueName = generateBenchmarkUniqueName(name, variables);
        checkArgument(uniqueName.equals(generatedUniqueName),
                "Passed unique benchmark name (%s) does not match generated one: (%s) - name: %s, variables: %s",
                uniqueName, generatedUniqueName, name, variables);

        BenchmarkRun benchmarkRun = benchmarkRunRepo.findForUpdateByUniqueNameAndSequenceId(uniqueName, sequenceId);
        if (benchmarkRun == null) {
            Environment environment = environmentService
                    .findEnvironment(environmentName.orElse(DEFAULT_ENVIRONMENT_NAME));
            benchmarkRun = new BenchmarkRun(name, sequenceId, variables, uniqueName);
            benchmarkRun.setStatus(STARTED);
            benchmarkRun.setEnvironment(environment);
            benchmarkRun.getAttributes().putAll(attributes);
            benchmarkRun.setStarted(currentDateTime());
            benchmarkRunRepo.save(benchmarkRun);
        }
        LOG.debug("Starting benchmark - {}", benchmarkRun);

        return benchmarkRun.getUniqueName();
    }

    @Retryable(value = { TransientDataAccessException.class, DataIntegrityViolationException.class })
    @Transactional
    public void finishBenchmarkRun(String uniqueName, String sequenceId, Status status, Optional<Instant> endTime,
            List<Measurement> measurements, Map<String, String> attributes) {
        BenchmarkRun benchmarkRun = findBenchmarkRun(uniqueName, sequenceId);
        benchmarkRun.getMeasurements().addAll(measurements);
        benchmarkRun.getAttributes().putAll(attributes);
        benchmarkRun.setEnded(fromInstantOrCurrentDateTime(endTime));
        benchmarkRun.setStatus(status);
        aggregateBenchmarkExecutions(benchmarkRun);
        LOG.debug("Finishing benchmark - {}", benchmarkRun);
    }

    private void aggregateBenchmarkExecutions(BenchmarkRun benchmarkRun) {
        benchmarkRun.clearAggregatedMeasurements();
        AggregatedMeasurement durationAggregatedMeasurement = benchmarkRun.getAggregatedMeasurements()
                .get("duration");
        if (durationAggregatedMeasurement != null) {
            benchmarkRun.setExecutionsMeanDuration(durationAggregatedMeasurement.getMean());
            benchmarkRun.setExecutionStdDevDuration(durationAggregatedMeasurement.getStdDev());
        }
    }

    @Retryable(value = { TransientDataAccessException.class, DataIntegrityViolationException.class })
    @Transactional
    public void startExecution(String uniqueName, String benchmarkSequenceId, String executionSequenceId,
            Map<String, String> attributes) {
        BenchmarkRun benchmarkRun = findBenchmarkRun(uniqueName, benchmarkSequenceId);

        boolean executionPresent = benchmarkRun.getExecutions().stream()
                .filter(e -> executionSequenceId.equals(e.getSequenceId())).findAny().isPresent();
        if (executionPresent) {
            LOG.debug("Execution ({}) already present for benchmark ({})", executionSequenceId, benchmarkRun);
            return;
        }

        LOG.debug("Starting new execution ({}) for benchmark ({})", executionSequenceId, benchmarkRun);
        BenchmarkRunExecution execution = new BenchmarkRunExecution();
        execution.setSequenceId(executionSequenceId);
        execution.setStatus(STARTED);
        execution.setStarted(currentDateTime());
        execution.setBenchmarkRun(benchmarkRun);
        execution.getAttributes().putAll(attributes);
        benchmarkRun.getExecutions().add(execution);
    }

    @Retryable(value = { TransientDataAccessException.class, DataIntegrityViolationException.class })
    @Transactional
    public void finishExecution(String uniqueName, String benchmarkSequenceId, String executionSequenceId,
            Status status, Optional<Instant> endTime, List<Measurement> measurements,
            Map<String, String> attributes) {
        BenchmarkRun benchmarkRun = findBenchmarkRun(uniqueName, benchmarkSequenceId);

        BenchmarkRunExecution execution = benchmarkRun.getExecutions().stream()
                .filter(e -> executionSequenceId.equals(e.getSequenceId())).findAny()
                .orElseThrow(() -> new IllegalStateException("Execution cannot be found"));

        checkState(execution.getStatus() == STARTED, "Wrong execution status: %s", execution.getStatus());

        execution.getMeasurements().addAll(measurements);
        execution.getAttributes().putAll(attributes);
        execution.setEnded(fromInstantOrCurrentDateTime(endTime));
        execution.setStatus(status);

        if (benchmarkRun.getStatus() != STARTED) {
            // Already finished and aggregated so needs re-aggregating.
            aggregateBenchmarkExecutions(benchmarkRun);
        }

        LOG.debug("Finishing execution - {}", execution);
    }

    @Transactional
    public BenchmarkRun findBenchmarkRun(String uniqueName, String sequenceId) {
        BenchmarkRun benchmarkRun = benchmarkRunRepo.findForUpdateByUniqueNameAndSequenceId(uniqueName, sequenceId);
        if (benchmarkRun == null) {
            throw new IllegalArgumentException("Could not find benchmark " + uniqueName + " - " + sequenceId);
        }
        Hibernate.initialize(benchmarkRun.getExecutions());
        Hibernate.initialize(benchmarkRun.getMeasurements());
        return benchmarkRun;
    }

    @Transactional(readOnly = true)
    public List<BenchmarkRun> findBenchmark(String uniqueName, String environmentName) {
        List<BenchmarkRun> benchmarkRuns = benchmarkRunRepo
                .findByUniqueNameAndEnvironmentOrderBySequenceIdDesc(uniqueName, findEnvironment(environmentName));
        for (BenchmarkRun benchmarkRun : benchmarkRuns) {
            Hibernate.initialize(benchmarkRun.getExecutions());
        }
        return benchmarkRuns;
    }

    private Environment findEnvironment(String environmentName) {
        return environmentService.findEnvironment(environmentName);
    }

    @Transactional(readOnly = true)
    public List<BenchmarkRun> findLatest(String environmentName) {
        return benchmarkRunRepo.findLatest(findEnvironment(environmentName).getId());
    }

    public String generateUniqueBenchmarkName(String name, Map<String, String> variables) {
        LOG.debug("Generating unique benchmark name for: name = {}, variables = {}", name, variables);
        return generateBenchmarkUniqueName(name, variables);
    }

    public Duration getSuccessfulExecutionAge(String uniqueName) {
        Timestamp ended = benchmarkRunRepo.findTimeOfLatestSuccessfulExecution(uniqueName);
        if (ended == null) {
            return Duration.ofDays(Integer.MAX_VALUE);
        }
        ZonedDateTime endedAsZDT = ZonedDateTime.of(ended.toLocalDateTime(), ZoneId.systemDefault());
        return Duration.between(endedAsZDT, currentDateTime());
    }

    private ZonedDateTime fromInstantOrCurrentDateTime(Optional<Instant> instant) {
        ZonedDateTime currentDateTime = currentDateTime();
        return instant.map(i -> i.atZone(currentDateTime.getZone())).orElse(currentDateTime);
    }
}