Trino/Prestoの互換性調査補助ツールを作った

Trino/Prestoをバージョンアップする際には事前に動作の互換性検証などを行なっているのですが、検証作業自体は以前Presto Conference Tokyo 2020でも紹介させていただいたquery-simulatorという内製のツールを使って自動化されているものの、実際に非互換の挙動を発見した後の原因調査(原因のコミットを特定してバグかどうかの判断をする)については引き続き地道な作業が必要な状態でした。

Trino/Pretsoは開発が非常にアクティブで、1回のリリースに数百のコミットが含まれます。1年程度バージョンアップを怠っているだけでも変更が巨大すぎてコードの変更履歴から原因を特定するのは非常に困難になります。そこで、まずは複数バージョンのTrino/Prestoでクエリの実行結果を比較することで変更が導入されたバージョンを特定し、その後、そのバージョンのコミットの中から原因となったコミットを調査するという作業を行なうことが多いのですが、このうちバージョンを特定する部分の作業は自動化できそうということでツールを作ってみました。

github.com

まだ、きちんとしたインターフェースを作っていないのでScalaコードを書いて実行する必要があるのですが、以下のようなコードで指定した範囲のバージョンのTrino/Prestoをdockerで起動し、クエリの実行結果を比較しつつ二分探索で変更が導入されたバージョンを自動的に検出してくれます。

import io.github.takezoe.trino.checker._

val checker = new BinaryVersionChecker(new DockerQueryRunner())
val results = checker.check(Range.inclusive(317, 350), "SELECT null GROUP BY 1, 1")
printResults(results)

実行結果はこんな感じになります。このケースでは339が変更が導入されたバージョンということになります。

✅ 317: Right(37a6259cc0c1dae299a7866489dff0bd)
❌ 350: Left(java.sql.SQLException: Query failed (#20210526_154140_00004_yzz4q): Multiple entries with same key: @38f546e: null=expr and @38f546e: null=expr)
✅ 334: Right(37a6259cc0c1dae299a7866489dff0bd)
❌ 342: Left(java.sql.SQLException: Query failed (#20210526_154251_00003_2km75): Multiple entries with same key: @63f11e0f: null=expr and @63f11e0f: null=expr)
✅ 338: Right(37a6259cc0c1dae299a7866489dff0bd)
❌ 340: Left(java.sql.SQLException: Query failed (#20210526_154338_00002_2xtvz): Multiple entries with same key: @76615946: null=expr and @76615946: null=expr)
❌ 339: Left(java.sql.SQLException: Query failed (#20210526_154358_00002_jdnni): Multiple entries with same key: @4aca599d: null=expr and @4aca599d: null=expr)

本当はコミットを特定するところまで自動化できると楽なのですが、バージョンを絞り込めばコミット履歴からあたりがつくこともありますし、実際に動かして動作確認するにしてもTrino/Prestoをソースからビルドする必要があるのでIDE上で実行したほうが早いかなという感じです。ニッチなツールなのでさほど頻繁に利用する機会はないかもしれませんが、こういった簡単なツールでも作業の効率化に役立つので、もっと早く作っておけばよかったなぁと思っています。