詳説 データベース ―ストレージエンジンと分散データシステムの仕組み

購入してからだいぶ時間がかかってしまいましたがようやく一周読み終わりました。元々は原著であるDatabase Internalsを読んでいたのですが、邦訳が出るという話を聞いて読み進める気力を失ってしまっていたのでした。

内容についてですが、データベースといってもクエリ言語やクエリの最適化といった製品依存度の高いトピックについては触れられておらず、データベースの種類を問わず普遍的なトピックであるストレージおよび分散システムに関するかなり硬派な内容になっています。

邦訳になっていることで確かに原著よりも早い速度で読むことはできるのですが、特に後半に関しては取り扱っている内容自体の難易度もあり、日本語で読んだから理解しやすいかというとそういうわけでもない感じでした。知見のあるトピックであれば理解できるのですが、そうでないトピックに関してはこの本だけではなかなか理解が難しい部分もあり、日本語で読んでも意味がわからないので原著と比べると確かに原著でもそう書いてあるんだけど、英語でそのまま読んだ方が理解しやすいかもと感じるケースもありました。

とはいえデータ指向アプリケーションデザインと同じく、自分で調べるきっかけを与えてくれるという意味ではとても貴重な教材だと思いますし、まずは興味のある部分だけを読んでいくというような読み方もありなのではないかと思います。アプリケーションの設計・開発にも応用の効くデータ指向アプリケーションデザインと比べるとデータベースに特化した書籍なので対象読者は絞られると思いますが(内容的には被る部分もありますが)、同様にじっくり理解を深めながら繰り返し読みたい一冊ですね。

データ指向アプリケーションデザインももう一度読みなさなくては…。

WDL(Workflow Description Language)について

Scalaベースのワークフローエンジンcromwellを試してみるの続きです。

cromwellではワークフローをWDL(Workflow Description Language)という言語で記述するようで*1、cromwellはWDLの参照実装という位置付けでもあるようです。WDLの仕様策定もcromwellを開発しているBroad Instituteのメンバーが中心に行われているようです。

github.com

WDLの基本的な記述方法については以下のドキュメントが参考になります。

github.com

support.terra.bio

WDLのサンプルGitHubリポジトリに含まれている簡単なワークフローを見てみます。

workflow SayItTwice {
   input {
     String name
   }
   call WriteGreeting {
      input:
         name = name
   }
   call ReadItBackToMe {
     input:
        written_name = WriteGreeting.output_name
  }
  output {
     File outfile = ReadItBackToMe.repeated_name
  }
}

task WriteGreeting {
  input {
     String name
  }

  command {
     echo "${name}"
  }
  output {
     File output_name = stdout()
  }
}

task ReadItBackToMe {
  input {
     File written_name
     String original_name = read_string(written_name)
  }

  command {
     echo "${original_name} to you too"
  }
  output {
     File repeated_name = stdout()
  }
}

taskでタスクを定義し、callで呼び出すという感じ。処理はcommandに外部コマンドを記述、タスクのouputで宣言した出力を別のタスクのinputで指定することでタスク間の依存関係を定義が定義されます。ワークフロー自体の入力は以下のようなJSONファイルで与えます。

{
  "SayItTwice.name": "Saying the same thing twice...is nice"
}

CLIで実行する場合、-iオプションでこのJSONファイルを指定します。

$ java -jar cromwell-<version>.jar run linear.wdl -i linear.json

このワークフローでは使われていませんが、runtimeを指定することでdockerコンテナで実行したり、scatter/gatherで集合を並列処理したりもできるようです。

WDL編集用にVSCodeのエクステンションの開発も進められているようです。あまりアクティブに開発されている感じではないっぽいですが…。

marketplace.visualstudio.com

*1:cromwellではWDL以外にCDL(Common Workflow Language)もサポートされています。

Scalaベースのワークフローエンジンcromwellを試してみる

ひょんなことからcromwellというScalaベースのワークフローエンジンの存在を知ったので軽く試してみました。依存関係を見るとAkka、Akka HTTP、Cats、Slickなどが使われているようです。

github.com

まずはGitHubのリリースページからcromwell-<version>.jarをダウンロードし、以下のようなシンプルなワークフローファイルを適当なファイル名(ここではhelloworld.wdlとします)で作成しておきます。

workflow myWorkflow {
    call myTask
}

task myTask {
    command {
        echo "hello world"
    }
    output {
        String out = read_string(stdout())
    }
}

CLIからワークフローを実行してみます。

$ java -jar cromwell-<version>.jar run helloworld.wdl

するとこんな出力が得られます。

{
  "outputs": {
    "myWorkflow.myTask.out": "hello world"
  },
  "id": "8904c84f-933d-4228-ba4e-7eef23a8b307"
}

ログを見るとデフォルトではhsqldbのインメモリモードで動作しているようです。設定ファイルのサンプルを見るとMySQLPostgreSQLも使えるようです。

続いでサーバーモードで実行してみます。以下のようにしてサーバーを起動します。

$ java -jar cromwell-<version>.jar server

ブラウザで http://localhost:8080 にアクセスするとSwaggerのUIを参照でき、このUIからファイルを指定してワークフローを実行したり、結果を確認したりできます。

f:id:takezoe:20210918221052p:plain

先ほどと同じワークフローをcurlコマンドで送信してみます。

$ curl -X POST http://localhost:8000/api/workflows/v1 -H "Content-Type: multipart/form-data" -F "workflowSource=@helloworld.wdl"

するとこんなJSONレスポンスが返ってきます。

{"id":"603775aa-d711-4df1-8bbb-1adad1ad7de4","status":"Submitted"}

ステータスを確認してみます。

$ curl http://localhost:8000/api/workflows/v1/603775aa-d711-4df1-8bbb-1adad1ad7de4/status
{"status":"Succeeded","id":"603775aa-d711-4df1-8bbb-1adad1ad7de4"}

成功しているようなので実行結果を参照してみます。

$ curl http://localhost:8000/api/workflows/v1/603775aa-d711-4df1-8bbb-1adad1ad7de4/outputs
{"outputs":{"myWorkflow.myTask.out":"hello world"},"id":"603775aa-d711-4df1-8bbb-1adad1ad7de4"}

CLIで実行した場合と同じ結果が得られました。

cromwellには様々な機能がありそうですし、WDLを使ったワークフローの記述などについてもエントリを改めてもう少し詳しく見ていきたいと思います。

GitHub Actionsでテストのエラーをわかりやすく表示する

CircleCIにはJUnit形式のテストレポートを食わせてテスト結果をわかりやすく表示してくれる機能があるのですが、GitHub Actionsでも同じようなことができないかなと思って調べてみたところ、以下のアクションを使えばできそうなので試してみました。

github.com

使い方は簡単で、テスト実行後にこんな感じの設定を追加するだけ。

- name: Publish Test Report
  uses: mikepenz/action-junit-report@v2
  if: always()
  with:
    report_paths: '**/build/test-results/test/TEST-*.xml'

Scalaプロジェクトの場合、sbtがtarget/test-reportsディレクトリ配下にJUnit形式のテストレポートを出力してくれるのでreport_pathsを以下のような感じにしておけばOKです。

report_paths: '**/target/test-reports/TEST-*.xml'

テストが失敗した場合、以下のように表示されます。失敗したテストケースとエラー内容を簡単に把握することができます。

f:id:takezoe:20210912122137p:plain

CIでテストが失敗した場合、どのテストがどういうエラーで失敗したのかをコンソールに出力されるログからすぐに見つけることが難しかったりするので、特にテストケースが大量にあるプロジェクトではこのアクションはなかなか便利そうです。

ジェットストリームプライムを試してみた

仕事や勉強などで物理ノートを使っているのですが、筆記具としてボールペンはジェットストリームの3色ボールペンを長らく愛用しています。ジェットストリームにはプライムというお値段高めの上位機種が存在するのですが、なんか変な宝石みたいのが付いてていまいち食指が動かなかったのですが、今年になってデザインが良い感じにリニューアルされたのでボールペンもちょっと良いものを使ってみようかと思い購入してみました。

数ヶ月使ってみての感想ですが、

  • デザインは良く、金属の重量感やマット塗装も相まって高級感はある
  • 通常の3色ジェットストリームと比べるとスリム
  • 通常のジェットストリームと違って持ち手部分がラバーではなく金属製なので長時間使っていると手が痛くなる
  • 重量はあるが重心は低いので重くて書きにくいということはない
  • ノックが特殊で慣れないと芯がうまく固定できなかったり筐体内で引っかかってしまうことがある
  • 替芯が専用のもので値段が高い。芯が透明ではないのでインクの残量がわからない
  • クリップが金属製なのは耐久性という意味では良いが固すぎる気がする

などなど、確かに高級感はあるのですが、実用性という意味では結構微妙な気も…。ベージュのモデルは塗装が異なるようなのでまた少し使い勝手が違うかもしれません。

また、プライムまではいかないのですが、通常のジェットストリームと比べると若干お値段高めの中位機種もあります。

こちらも実際に購入してしばらく使ってみました。

  • 見た目の高級感やマットな手触りなどはプライムに近いものがあるが金属製ではないので軽量
  • プライムと違ってスリム筐体ではないがラックのノックがクリップに割り当てられているので通常の3色モデルと比べるとスッキリしている
  • やはりノック(特にクリップに割り当てられたブラック)が特殊で慣れないとうまく固定できないことがある
  • 持ち手部分はラバーなので長時間使っても指が痛くならない
  • 芯は普通の多色ジェットストリームと同じものが使えるのでランニングコストはいい

というわけで色々試してはみたものの、なんだかんだで今まで使っていたスタンダードな三色モデルが一番使いやすいのではという身も蓋もない結論に達してしまいました!

安いので雑に扱っても気が咎めないし、壊れたり失くしたりしても買い換えればいいかという気になりますし…。本体、替芯ともにスーパーの文房具売り場などでも比較的入手しやすいのも実用性高いです。とはいえジェットストリームは様々なバリエーションがありますし、コラボでいろんなデザインの筐体を限定で出したりしてるので、自分好みのモデルを見つけたら芯を交換して使い続けられるのはいいところですね。

今回はボールペンについてでしたが、仕事で使う文房具に関してはノートや付箋なども色々と試しているので、また機会があれば書いてみたいと思います。

GitBucket 4.36.0をリリースしました

Scalaで実装されたオープンソースのGitサーバ、GitBucket 4.36.0をリリースしました。

https://github.com/takezoe/gitbucket/releases/tag/4.36.0

リポジトリビューアでのタグ選択

リポジトリビューアのブランチ選択用プルダウンでタグを選択することもできるようになりました。

f:id:takezoe:20210717231624p:plain

リポジトリのIssue/Pull Requestへのリンク

これまでもマークダウン内での#123のような記述はリポジトリ内のIssue/Pull Requestへのリンクとしてレンダリングされていましたが、これに加えてuser/repo#123のような記述で別リポジトリのIssue/Pull Requestへのリンクを生成できるようになりました。

f:id:takezoe:20210717231641p:plain

差分ビューのファイル、行へのリンク

差分ビューで各ファイル、行にリンク用の識別子が生成されるようになりました。以下のようにしてリンクすることができます。

f:id:takezoe:20210717231654p:plain

f:id:takezoe:20210717231713p:plain

XSSプロテクション無効化オプションを追加

リポジトリビューアではXSS防止のため特定の種類のファイルは描画しないようになっていますが、この挙動をリポジトリのオプションで変更できるようになりました。このオプションはGitリポジトリに格納されているこれらのファイルをHTML等に貼り付けたい場合に利用できますが、公開リポジトリでは有効にしないよう注意してください。

f:id:takezoe:20210717231733p:plain

今回のバージョンではこの他にも様々な改善やバグフィックスを行っています。詳細についてはIssueの一覧をご覧ください。

trino-client-ruby 1.0.0をリリースしました

トレジャーデータが公開しているOSSの1つにpresto-client-rubyというRuby用のPrestoクライアントライブラリがあり、最近色々と弄る機会が増えてきたのでメンテナにしていただいたのですが、PrestoSQLがTrinoのリブランディングされ通信の仕様も若干変わったため、Trino対応させるとともにtrino-client-rubyに改名し、バージョンも1.0.0としてリリースし直しました。

github.com

PrestoはレスポンスのJSONの形式がバージョンによって若干異なるため、presto-client-rubyではmodel_versionというオプションで使用するPrestoのモデルを指定できるようになっているのですが、このオプションで351以前のバージョンを指定するとPrestoモードで動作するようになっています。デフォルトではTrinoモードで動作します。

client = Trino::Client.new(
  server: "localhost:8880",
  ssl: {verify: false},
  catalog: "native",
  schema: "default",
  ...
  model_version: "316" # Works in Presto mode
)

ただ、model_versionオプションは必ずしも対象のPrestoのバージョンをそのまま指定すればよいというわけではなく、ちょっとわかりにくい部分もあるのでクライアントのインスタンス生成時にPresto/Trinoのバージョンを確認しに行って自動で判定するようにしてもいいかもしれないと思っています。

今後も改善できる点があれば引き続きメンテしていきたいと思います。