すぴすらのろぐ

読んだもののメモとかポエムとか

トランザクション間の隠れた制約の表現と解釈

前回のポストで、アプリケーションに対するゼロ知識モデルではトランザクション間に隠れた制約(hidden restrictions)があると考えざるを得ないと書きました。

本ポストでは、トランザクション間の隠れた制約(が限定的であること)をどのように表現してスケジューラに伝えればよいか、およびスケジューラはそれをどのように扱えばよいかについてまとめました。

用語(再掲)

トランザクション間の)隠れた制約

例えばトランザクションの間に、スケジューラが関与しない形で事前に順序が決められていたり、あるトランザクションの結果がデータベースの外部で別のトランザクションへ影響を及ぼしているような場合、それらのトランザクションの間には、直列化可能なスケジューリングに対する制約が存在することになります。このような制約を、トランザクション間の隠れた制約(hidden restriction)と呼びます*1

隠れた制約の表現

ここでは、あるトランザクションによってトランザクションの外側へ影響を与えることを、そのトランザクションと外側の何かの間のメッセージ通信だと解釈することにします。同様に、トランザクションの外側から影響を受けることも外側とトランザクションの間のメッセージ通信だと解釈します。
外側の何かを、ここでは環境と呼ぶことにします*2

つまり、トランザクショントランザクションの開始時点の環境からメッセージを受取り、トランザクションの完了(コミット)によって環境にメッセージが送られるというモデルです。

メッセージ通信を read と write で表現すると、メッセージの送信が write でメッセージの受信が read です。

トランザクションを主体に考えると、トランザクションの開始は環境からの read 、トランザクションの完了(コミット)は環境への read+write で表現できます*3

read が開始時点で write がコミット時点である理由は前回のポストに書いた通り、トランザクションはアトミックで完全に分離したいものである、という前提に立つためです。

環境の表現

一番簡単な環境の表現は、唯一の環境があると考える方法です。
この場合、環境から影響を受けている or 環境に影響を与えるトランザクションなのか、そうではないのかを表現できます。

しかし実用においては解像度が低すぎると思うので、ここでは単一のルートを持つ階層構造の名前空間を環境に導入することにします。

名前空間により、たとえばユーザ毎の環境(コンテキスト)があり、個々のトランザクションは対象のユーザの環境には依存しているが他のユーザの環境とは無関係である、といったことが表現可能になります。

また階層構造を持つことで、全ユーザの統計のようなものを持つ環境を表現することもできます。
階層構造を持つ場合、ある名前の環境に対する write は、その配下すべてと、それを含む上位すべてを変更する(アップデートする)と解釈します。

アプリケーションによる宣言

アプリケーションは、自身が参照する(影響を受ける)環境の名前をスケジューラに通知します。同様に、自身が作用する(影響を与える)環境の名前をスケジューラに通知します。両者は通常は同じとしても良いかもしれません。

これによってトランザクション間のつながりが、環境によって表現できます。

アプリケーションによる環境の指定がない場合は、(ゼロ知識原理主義に乗っ取り)アプリケーションはルート環境から影響を受け、ルート環境に影響を及ぼすと解釈します。

スケジューラにおける解釈

スケジューラは環境をある特別なエンティティとして、データベースエンティティと同様に扱うことで、自然に隠れた制約を考慮したスケジューリングを行うことができます*4
ただし環境はモノバージョンであって、過去を参照することはできません。

まとめとか

このような指定をアプリケーションが行いそれを DBMS が解釈可能であったとすると、例えば同一ユーザIDにおいては external consistency が必要だが異なるユーザID間では結果整合性であっても良い、といったことが表現可能になるはずです。
このような指定により、DBMS(スケジューラ)によるスケジューリングの自由度が高まり、アボート可能性が減ったりスループットが向上するといったメリットを享受できるようになるかもしれません。

一方で、同一ユーザIDで厳密な整合性が必要なら、DBMS の実装はあまり変わらない可能性もありそうです。
ただし、同一ユーザIDは同時に一つのセッションでしかアクセスできない、というような制約を加えることで、DBMS の実装を簡単にできる余地が生まれるかもしれません。

懸念は、アプリケーションが自身が関与する環境を正しく宣言できるか、および環境の階層構造を正しく定義できるか、といったあたりです。

また、環境には必然的に人間が(人間の認識や記憶が)含まれることになります*5
そのため、アプリケーションは関係がないと定義したが、人間はその(環境を通じた関係においては無関係なはずの)別のトランザクションの結果を知っていて、その不整合さに違和感を覚える可能性があります。

この辺りの対応を考慮すると、唯一の環境が存在することにしてしまえ、という気分になるのかもしれません*6

直列化可能なトランザクションにおいては、トランザクションによるデータベースからの read はトランザクションの開始時点(以前)のものであり、トランザクションによるデータベースへの write はトランザクションのコミット時点(以降)に初めて顕在化します。これは、環境に対する read/write と対称となっています。

f:id:dev_supisula:20200505020212p:plain

トランザクション間の隠れた制約がないとするモデルは、トランザクションの外側にメッセージ通信を媒介するステートが存在しないと考えていると解釈できます*7。そのため、すべて(スケジューリング)はデータベース主体で考えることができます。

一方でトランザクション間に隠れた制約があるとするモデル、つまりデータベースの外側にもステートがあるとみなすモデルでは、スケジューラは実時間(もしくは時間の一方向性)を無視したスケジューリングを行うことができません*8

(分散処理の文脈の)consistency が重要になってきたのは、シングルノードでは簡単だが分散環境では難しいからという話なのだと思いますが、一方では、人間と計算機の間の界面が、より人間寄りにシフトしてきたことによりデータベース外のステートの重要性が増した結果であるとも、個人的には思います*9

*1:papa本より

*2:もしくはコンテキストとか

*3:write ではなく read+write である理由は、ページモデルにおいて write が、対象の完全な書換え(上書き)と解釈されてしまうためです。部分的な変更やアップデートを表現する場合は read 後の write と表現する必要があります。また環境への変更は可換である(もしくはその環境への新規アイテムのinsert である)と解釈しないと後述のスケジューリングが大変になるかもしれません。

*4:環境を通じた reads-from関係がトランザクション間の順序を規定するの意

*5:記憶を持つもの全体の集合からデータベースを除いたものが環境であるため

*6:external consistency を提供してしまおうという気分

*7:すべての状態はデータベースに保存されている!

*8:時間の一方向性に基づく記憶・記録が外部に存在し、それとの不一致を検出可能であるから

*9:SoR から SoE へ、のような。もしくは human-centric とか。