Skip to content

Commit

Permalink
Export determinism analysis details
Browse files Browse the repository at this point in the history
  • Loading branch information
caithagoras0 authored and mbasmanova committed Dec 4, 2019
1 parent 7cedd37 commit bba5aa2
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 76 deletions.
5 changes: 5 additions & 0 deletions presto-verifier/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
<artifactId>presto-thrift-connector</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.facebook.presto.verifier.event;

import com.facebook.airlift.event.client.EventField;
import com.facebook.airlift.event.client.EventType;
import com.facebook.presto.verifier.framework.LimitQueryDeterminismAnalysis;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.collect.ImmutableList;

import javax.annotation.concurrent.Immutable;

import java.util.List;
import java.util.Optional;

@Immutable
@EventType("DeterminismAnalysisDetails")
public class DeterminismAnalysisDetails
{
private final List<DeterminismAnalysisRun> runs;
private final String limitQueryAnalysis;
private final String limitQueryAnalysisQueryId;

@JsonCreator
public DeterminismAnalysisDetails(
List<DeterminismAnalysisRun> runs,
LimitQueryDeterminismAnalysis limitQueryAnalysis,
Optional<String> limitQueryAnalysisQueryId)
{
this.runs = ImmutableList.copyOf(runs);
this.limitQueryAnalysis = limitQueryAnalysis.name();
this.limitQueryAnalysisQueryId = limitQueryAnalysisQueryId.orElse(null);
}

@EventField
public List<DeterminismAnalysisRun> getRuns()
{
return runs;
}

@EventField
public String getLimitQueryAnalysis()
{
return limitQueryAnalysis;
}

@EventField
public String getLimitQueryAnalysisQueryId()
{
return limitQueryAnalysisQueryId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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.facebook.presto.verifier.event;

import com.facebook.airlift.event.client.EventField;
import com.facebook.airlift.event.client.EventType;

import javax.annotation.concurrent.Immutable;

import java.util.Optional;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

@Immutable
@EventType("DeterminismAnalysisRun")
public class DeterminismAnalysisRun
{
private final String tableName;
private final String queryId;
private final String checksumQueryId;

private DeterminismAnalysisRun(
Optional<String> tableName,
Optional<String> queryId,
Optional<String> checksumQueryId)
{
this.tableName = tableName.orElse(null);
this.queryId = queryId.orElse(null);
this.checksumQueryId = checksumQueryId.orElse(null);
}

@EventField
public String getTableName()
{
return tableName;
}

@EventField
public String getQueryId()
{
return queryId;
}

@EventField
public String getChecksumQueryId()
{
return checksumQueryId;
}

public static Builder builder()
{
return new Builder();
}

public static class Builder
{
private String tableName;
private String queryId;
private String checksumQueryId;

private Builder()
{
}

public Builder setTableName(String tableName)
{
checkState(this.tableName == null, "tableName is already set");
this.tableName = requireNonNull(tableName, "tableName is null");
return this;
}

public Builder setQueryId(String queryId)
{
checkState(this.queryId == null, "queryId is already set");
this.queryId = requireNonNull(queryId, "queryId is null");
return this;
}

public Builder setChecksumQueryId(String checksumQueryId)
{
checkState(this.checksumQueryId == null, "checksumQueryId is already set");
this.checksumQueryId = requireNonNull(checksumQueryId, "checksumQueryId is null");
return this;
}

public DeterminismAnalysisRun build()
{
return new DeterminismAnalysisRun(Optional.ofNullable(tableName), Optional.ofNullable(queryId), Optional.ofNullable(checksumQueryId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public enum EventStatus

private final Boolean deterministic;
private final String determinismAnalysis;
private final DeterminismAnalysisDetails determinismAnalysisDetails;
private final String resolveMessage;

private final QueryInfo controlQueryInfo;
Expand All @@ -66,6 +67,7 @@ public VerifierQueryEvent(
EventStatus status,
Optional<SkippedReason> skippedReason,
Optional<DeterminismAnalysis> determinismAnalysis,
Optional<DeterminismAnalysisDetails> determinismAnalysisDetails,
Optional<String> resolveMessage,
Optional<QueryInfo> controlQueryInfo,
Optional<QueryInfo> testQueryInfo,
Expand All @@ -81,6 +83,7 @@ public VerifierQueryEvent(
this.skippedReason = skippedReason.map(SkippedReason::name).orElse(null);
this.deterministic = determinismAnalysis.filter(d -> !d.isUnknown()).map(DeterminismAnalysis::isDeterministic).orElse(null);
this.determinismAnalysis = determinismAnalysis.map(DeterminismAnalysis::name).orElse(null);
this.determinismAnalysisDetails = determinismAnalysisDetails.orElse(null);
this.resolveMessage = resolveMessage.orElse(null);
this.controlQueryInfo = controlQueryInfo.orElse(null);
this.testQueryInfo = testQueryInfo.orElse(null);
Expand Down Expand Up @@ -109,6 +112,7 @@ public static VerifierQueryEvent skipped(
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
ImmutableList.of());
}

Expand Down Expand Up @@ -155,6 +159,12 @@ public String getDeterminismAnalysis()
return determinismAnalysis;
}

@EventField
public DeterminismAnalysisDetails getDeterminismAnalysisDetails()
{
return determinismAnalysisDetails;
}

@EventField
public String getResolveMessage()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.facebook.presto.sql.SqlFormatter;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.verifier.checksum.ChecksumResult;
import com.facebook.presto.verifier.event.DeterminismAnalysisDetails;
import com.facebook.presto.verifier.event.QueryInfo;
import com.facebook.presto.verifier.event.VerifierQueryEvent;
import com.facebook.presto.verifier.event.VerifierQueryEvent.EventStatus;
Expand Down Expand Up @@ -274,6 +275,12 @@ else if (skippedReason.isPresent()) {
status,
skippedReason,
determinismAnalysis,
determinismAnalysis.isPresent() ?
Optional.of(new DeterminismAnalysisDetails(
verificationContext.getDeterminismAnalysisRuns(),
verificationContext.getLimitQueryAnalysis(),
verificationContext.getLimitQueryAnalysisQueryId())) :
Optional.empty(),
resolveMessage,
Optional.of(buildQueryInfo(
sourceQuery.getControlConfiguration(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import com.facebook.presto.verifier.checksum.ChecksumResult;
import com.facebook.presto.verifier.checksum.ChecksumValidator;
import com.facebook.presto.verifier.checksum.ColumnMatchResult;
import com.facebook.presto.verifier.event.DeterminismAnalysisRun;
import com.facebook.presto.verifier.framework.MatchResult.MatchType;
import com.facebook.presto.verifier.prestoaction.PrestoAction;
import com.facebook.presto.verifier.resolver.FailureResolverManager;
import com.facebook.presto.verifier.rewrite.QueryRewriter;
import com.google.common.collect.ImmutableMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -47,6 +49,7 @@
import static com.facebook.presto.verifier.framework.QueryStage.CHECKSUM;
import static com.facebook.presto.verifier.framework.QueryStage.DESCRIBE;
import static com.facebook.presto.verifier.framework.VerifierUtil.callWithQueryStatsConsumer;
import static com.facebook.presto.verifier.framework.VerifierUtil.runWithQueryStatsConsumer;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -99,28 +102,33 @@ public MatchResult verify(QueryBundle control, QueryBundle test)
}

@Override
protected DeterminismAnalysis analyzeDeterminism(QueryBundle control, ChecksumResult firstChecksum)
protected DeterminismAnalysis analyzeDeterminism(QueryBundle control, ChecksumResult controlChecksum)
{
List<Column> columns = getColumns(control.getTableName());
List<QueryBundle> queryBundles = new ArrayList<>();

QueryBundle secondRun = null;
QueryBundle thirdRun = null;
try {
secondRun = getQueryRewriter().rewriteQuery(getSourceQuery().getControlQuery(), CONTROL);
setupAndRun(secondRun, true);
DeterminismAnalysis determinismAnalysis = matchResultToDeterminism(match(columns, columns, firstChecksum, computeChecksum(secondRun, columns).getResult()));
if (determinismAnalysis != DETERMINISTIC) {
return determinismAnalysis;
for (int i = 0; i < 2; i++) {
QueryBundle queryBundle = getQueryRewriter().rewriteQuery(getSourceQuery().getControlQuery(), CONTROL);
queryBundles.add(queryBundle);
DeterminismAnalysisRun.Builder run = getVerificationContext().startDeterminismAnalysisRun().setTableName(queryBundle.getTableName().toString());

runWithQueryStatsConsumer(() -> setupAndRun(queryBundle, true), stats -> run.setQueryId(stats.getQueryId()));

Query checksumQuery = checksumValidator.generateChecksumQuery(queryBundle.getTableName(), columns);
ChecksumResult testChecksum = getOnlyElement(callWithQueryStatsConsumer(
() -> executeChecksumQuery(checksumQuery),
stats -> run.setChecksumQueryId(stats.getQueryId())).getResults());

DeterminismAnalysis determinismAnalysis = matchResultToDeterminism(match(columns, columns, controlChecksum, testChecksum));
if (determinismAnalysis != DETERMINISTIC) {
return determinismAnalysis;
}
}

thirdRun = getQueryRewriter().rewriteQuery(getSourceQuery().getControlQuery(), CONTROL);
setupAndRun(thirdRun, true);
determinismAnalysis = matchResultToDeterminism(match(columns, columns, firstChecksum, computeChecksum(thirdRun, columns).getResult()));
if (determinismAnalysis != DETERMINISTIC) {
return determinismAnalysis;
}
LimitQueryDeterminismAnalysis analysis = limitQueryDeterminismAnalyzer.analyze(control, controlChecksum.getRowCount(), getVerificationContext());
getVerificationContext().setLimitQueryAnalysis(analysis);

LimitQueryDeterminismAnalysis analysis = limitQueryDeterminismAnalyzer.analyze(control, firstChecksum.getRowCount());
switch (analysis) {
case NON_DETERMINISTIC:
return NON_DETERMINISTIC_LIMIT_CLAUSE;
Expand All @@ -140,8 +148,7 @@ protected DeterminismAnalysis analyzeDeterminism(QueryBundle control, ChecksumRe
return ANALYSIS_FAILED;
}
finally {
teardownSafely(secondRun);
teardownSafely(thirdRun);
queryBundles.forEach(this::teardownSafely);
}
}

Expand Down Expand Up @@ -208,46 +215,4 @@ private QueryResult<ChecksumResult> executeChecksumQuery(Query query)
{
return getPrestoAction().execute(query, CHECKSUM, ChecksumResult::fromResultSet);
}

private ChecksumQueryAndResult computeChecksum(QueryBundle bundle, List<Column> columns)
{
Query checksumQuery = checksumValidator.generateChecksumQuery(bundle.getTableName(), columns);
QueryResult<ChecksumResult> queryResult = getPrestoAction().execute(
checksumQuery,
CHECKSUM,
ChecksumResult::fromResultSet);
return new ChecksumQueryAndResult(
queryResult.getQueryStats().getQueryId(),
checksumQuery,
getOnlyElement(queryResult.getResults()));
}

private class ChecksumQueryAndResult
{
private final String queryId;
private final Query query;
private final ChecksumResult result;

public ChecksumQueryAndResult(String queryId, Query query, ChecksumResult result)
{
this.queryId = requireNonNull(queryId, "queryId is null");
this.query = requireNonNull(query, "query is null");
this.result = requireNonNull(result, "result is null");
}

public String getQueryId()
{
return queryId;
}

public Query getQuery()
{
return query;
}

public ChecksumResult getResult()
{
return result;
}
}
}
Loading

0 comments on commit bba5aa2

Please sign in to comment.