# 分散トランザクション - 続き

![`smart`](PercolatorTiKV03_aa_002_20220511.png)

------------------------------------------------------------
ここからトランザクションが始まります：
```
Begin
< 1,Tom > -> < 1,Jack >
< 2,Andy > -> < 2,Candy > 
Commit;
```

key = 1 と key = 2 が、異なるリージョンで異なるTiKVノード上にあると仮定します。

最初に、トランザクションの始めに、PDからstart_tsを取得し、100と仮定しました。そして、Percolatorの最初の段階であるPreWriteに入りました。この時点では、トランザクションはまだコミットされていないので、Lock CFとDefault CFに書き込むだけです。図からわかるように、Default CFに書き込むときに、キーにタイムスタンプ（start_ts）を追加しました。Lock CFの2つの値は異なりますが、主にlock_type、user_key、start_tsを含みます。

（W は書くことを示し、D は削除を示します）。
```
+****************************************************************************+
|                                              Key = 1                       |
+***********************+*********************************+******************+
|   Default CF      |            Lock CF             ｜      Write CF         |
+***********************+*******+**************************+*******+*********+
|   key  |  value   |  key |       value             |   key   |   value     |
+***********************+*******+********************************************+
| 1_100  |   Jack   |   1  |  W, primary key,100...  |         |             |
+***********************+*******+**************************+*****************+

+****************************************************************************+
|                                              Key = 2                       |
+***********************+*********************************+******************+
|        Default CF          |               Lock CF        ｜   Write CF     |
+***********************+*******+**************************+*******+*********+
|   key        |  value      |    key  |         value      |   key |  value |
+***********************+*******+********************************************+
|   2_100      |   Candy     |     2   |  W, @key = 1,00... |       |        |
+***********************+*******+**************************+*****************+
```

一つ重要なポイントとして、key = 1 と key = 2 がトランザクション内で変更されることに注意してください。Lock CF では、最初に変更されたキー、key = 1 がプライマリキーとして使用され、key = 2 のロックは key = 1 に向けられます（つまり、Lock CF の値）。これは、key = 2 のロックが key = 1 のロックに付随することを意味します。

Default CFでデータを修正または削除する場合、既存のデータを修正または削除する代わりに新しいキー-値ペアが挿入されます。これは、Default CFがMVCC（マルチバージョン並行制御）技術を使用しているためです。この技術により、複数のトランザクションが同じデータに同時にアクセスできますが、互いに干渉しません。Default CFでトランザクションがデータを修正または削除すると、新しいタイムスタンプの新しいバージョンのデータが作成され、古いバージョンは修正または削除されません。これにより、既に古いバージョンのデータにアクセスしている他のトランザクションが、現在のトランザクションが行った修正や削除の影響を受けずにそれを継続して使用できます。この詳細は、MVCC技術を導入するときにさらに説明します。

次に、Percolatorの2番目のステージであるCommitに入ります。この時点でPDからcommit_tsを取得し、仮に110とします。そして、このcommit_tsをWrite CFに書き込み、トランザクションのstart_tsの値にタイムスタンプ（commit_ts）を追加します。また、Lock CFのプライマリキーレコードをDでマークして、トランザクションがコミットされ、ロックがもう必要ないことを示します。これでトランザクションのCommitステージが完了しました。

（W は書くことを示し、D は削除を示します）。
```
+************************************************************************************+
|                                              Key = 1                               |
+***********************+*********************************+**************************+
|        Default CF         |               Lock CF              ｜     Write CF     |
+***********************+*******+**************************+*******+*****************+
|   key       |  value      |    key  |         value            |   key   |   value |
+***********************+*******+****************************************************+
| 1_100       |   Jack      |     1   |  W, primary key,100...   |         |         |
+***********************+*******+**************************+*************************+
|             |             |     1   |  D,  primary key,100...  |         |         |
+***********************+*******+**************************+*************************+

+**************************************************************************************+
|                                              Key = 2                                 |
+***********************+*********************************+****************************+
|        Default CF         |               Lock CF          ｜           Write CF      |
+***********************+*******+**************************+*******+*******************+
|   key        |  value     |    key  |        value         |   key   |   value       |
+***********************+*******+******************************************************+
| 2_100        |   Candy    |     2   |  W, @key = 1,00...   |         |               |
+***********************+*******+**************************+***************************+
|              |            |     2   |  D,  @key = 1,00...  |  2_110  | start_ts=100  |
+***********************+*******+**************************+***************************+
```

コミットステージが完了した後、データを読み取りたい場合、まずLock CFにデータにロックがあるかどうかを確認します。ロックがない場合、またはロックが削除されている（すなわちフラグがDの場合）場合、データを読み取ることができます。そうでない場合は、まだ完了していないトランザクションによってデータがロックされているため、読み取りは失敗します。これにより、同時トランザクションが互いに分離され、データが他のトランザクションによってコミットされるまでは、他方のトランザクションから読み取られないようにします。

コミットフェーズ中のPercolatorでは、キー=1のプライマリキーを削除するだけで済むことが分かりました。これは、キー=2のLock CFにキー=1のプライマリキーへのポインタが含まれているからです。キー=1のみが削除されるエラーが発生した場合でも、キー=2のLock CFを確認することでトランザクションが正常に送信されたかどうかを判断できます。このソリューションにより、先ほど述べた分散トランザクションの問題が解決されました。

私たちは、Percolatorモデルへの簡単な紹介だけを提供しました。実際の実装はもっと複雑になるでしょう。
