アトミックコミット

**[[不可分操作|アトミック]][[コミット (データ管理)|コミット]]** (英: atomic commit)は、計算機科学の分野では、一連の個別の変更が単一の処理として実行される処理のことである。すべての変更が適用された場合、アトミックコミットは成功したと表現される。アトミックコミットの完了を待たずに障害が発生した場合、それより先に完了したすべての変更は元に戻される。これにより、システムは常に一貫した状態に保たれる。また、このような不可分操作としての性質に由来するもう一つの重要な特性として、独立性がある。独立性は、一度に一つのアトミックコミットの処理が行われることを保障する。アトミックコミットの最も一般的な用途は、データベースシステムとバージョン管理システムである。

アトミックコミットの課題は、複数システム間の調整が必要なことである。 コンピュータネットワークは信頼性の低いサービスであり、これは、二人の将軍問題で証明されているように、すべてのシステムと調整できるアルゴリズムがないことを意味する。データベースの分散化が進むにつれて、真のアトミックコミットを行うことが難しくなる。 

## 例
アトミックコミットは、データのマルチステップ更新に不可欠である。これは、2つの当座預金口座間の送金の簡単な例で明確に示すことができる。 

この例は、口座XからYに10,000円を送金するトランザクション中に、口座Yの残高をチェックするトランザクションが発生することで複雑になる。最初に、10,000円が口座Xから削除される。次に、10,000円が口座Yに追加される。ここで、操作全体が1つのアトミックコミットとして完了しない場合、いくつかの問題が発生しうる。たとえば、Xからお金を削除した後、Yに追加する前にシステムに障害が発生した場合、10,000円が消えてしまう可能性がある。また、10,000円を追加する前にYの残高を確認すると、Yの間違った残高が報告される可能性があるという問題もある。

アトミックコミットでは、これらのケースのどちらも発生しない。システム障害の最初のケースでは、アトミックコミットがロールバックされ、お金がXに返される。2番目のケースでは、Yの残高の要求はアトミックコミットが完全に完了するまで発生しない。

## データベースシステムにおける利用
データベースシステムでのアトミックコミットは、 ACIDの2つの重要な特性である不可分性と一貫性を満たす。一貫性は、アトミックコミットの各変更が一貫している場合にのみ達成される。

先の例のように、アトミックコミットは、データベースでのマルチステップ操作にとって重要である。しかし近代的なハードウェア設計により、データベースが存在する物理ディスク上で、真のアトミックコミットは存在しえない。

ディスクに書き込むことができる最小の領域は、ディスクセクタと呼ばれる。 1つのデータベースエントリは、複数の異なるセクタにまたがる場合もあるが、一度に書き込むことができるセクタは1つだけである。この書き込み制限が、真のアトミックコミットが不可能な理由である。メモリ内のデータベースエントリが変更された後、それらはディスクに書き込まれるためにキューに入れられる。これは、例で特定されたのと同じ問題が再発したことを意味する。この問題は、どんなアルゴリズムを使っても必ず二人の将軍問題に遭遇し完全な解決ができない。2相コミットと3相コミットの手法は、アトミックコミットと関連するいくつかの問題を一部解決する。

2相コミットプロトコルでは、調整者が、問題が発生した場合にデータベースの元の状態を回復するために必要なすべての情報を維持する必要がある。名前が示すように、投票とコミットの2つのフェーズがある。

投票フェーズでは、各ノードがアトミックコミットの変更を独自のディスクに書き込む。次に、ノードはその状態を調整者に報告する。いずれかのノードが調整者に報告しないか、状態メッセージが失われた場合、調整者はノードの書き込みが失敗したと見なす。すべてのノードが調整者に報告すると、第2フェーズが始まる。

コミットフェーズ中に、調整者は各ノードにコミットメッセージを送信して、個々のログに記録する。このメッセージがノードのログに追加されるまで、加えられた変更はすべて不完全として記録される。いずれかのノードが障害を報告した場合、調整者は代わりにロールバックメッセージを送信する。これにより、ノードがディスクに書き込んだ変更がすべて削除される。 

3相コミットプロトコルは、2相コミットプロトコルの主な問題を取り除くことを目的としている。これは、コミットフェーズ中に調整者と別のノードに同時に障害が発生した場合に発生し、どちらのアクションも実行すべきかを判断できない。この問題を解決するために、3番目のフェーズがプロトコルに追加される。コミット準備フェーズは、投票フェーズの後、コミットフェーズの前に発生する。

投票フェーズでは、2相コミットと同様に、調整者は各ノードがコミットする準備ができていることを要求する。いずれかのノードに障害が発生した場合、調整者は障害が発生したノードを待機している間にタイムアウトする。これが発生した場合、調整者はすべてのノードに中止メッセージを送信する。いずれかのノードが失敗メッセージを返した場合も、同じアクションが実行される。

投票フェーズで各ノードから成功メッセージを受信すると、コミット準備フェーズが開始される。このフェーズでは、調整者は各ノードに準備メッセージを送信する。各ノードは、準備メッセージを確認して応答する必要がある。応答がない場合、またはノードが準備ができていないことを返す場合、調整者は中止メッセージを送信する。タイムアウトが経過する前に準備メッセージを受信しないノードは、コミットを中止する。

すべてのノードが準備メッセージに応答した後、コミットフェーズが開始される。このフェーズでは、調整者は各ノードにコミットメッセージを送信する。各ノードはこのメッセージを受信すると、実際のコミットを実行する。メッセージが失われたためにコミットメッセージがノードに到達しない場合、または調整者が失敗した場合、タイムアウトが経過するとコミットが実行される。調整者がリカバリー時に失敗した場合、調整者は各ノードにコミットメッセージを送信する。 

## バージョン管理における利用
アトミックコミットはバージョン管理システムの一般的な機能であり、リポジトリ内の一貫した状態を維持するために重要である。 ほとんどのバージョン管理ソフトウェアは、失敗したコミットのどの部分も適用しない。(例外は、CVS、VSS、IBM Rational ClearCase (UCMモードの場合)。)

たとえば、バージョン管理ソフトウェアで、自動的に解決できない統合の競合が発生した場合、変更セットのどの部分も統合されない。代わりに、開発者には、変更を元に戻すか、競合を手動で解決する機会が与えられる。

これにより、部分的に適用された変更セットが原因でプロジェクト全体が壊れた状態になるのを防ぐ。コミットからの1つのファイルは正常にコミットされるが、依存する変更がある別のファイルは失敗する。 

アトミックコミットは、モノレポと呼ばれるバージョン管理ソフトウェア開発戦略を使用して、バージョン管理ソフトウェアを使用して複数のプロジェクト間で同時に変更を行う機能を指す場合もある。 

## コミット運用手法としてのアトミックコミット
バージョン管理システムを使用する場合、小さなコミットを行うことが一般的に推奨される。影響範囲がシステムの単一の側面にのみ限定される (はずである)ため、このような手法をアトミックコミットと呼ぶこともある。この手法により、理解が簡単になり、変更をロールバックする労力が減り、バグの特定が容易になる。 

コミットのサイズが小さく、焦点が絞られているほど、理解はより簡単になる。 1種類の変更のみを探している場合、何が変更され、変更の背後にある理由を理解するのがはるかに簡単になる。これは、ソースコードの書式を変更するときに特に重要になる。書式と機能変更を同時に行うと、有用な変更を特定することが非常に困難になる。ファイル内のスペースが、すべてタブ文字から3つの空白文字に変更された場合を想像してほしい。同時に機能の変更も行われた場合、レビュー担当者が機能の変更箇所を特定するのは容易ではなくなるため、このような変更方法は推奨されない。 

アトミックコミットのみを行うようにすることで、エラーを引き起こすコミットの識別がはるかに簡単になる。エラーの原因であるかどうかを確認するために、すべてのコミットを調べる必要がなく、その機能を処理するコミットのみを調べればよい。エラーをロールバックする場合は、アトミックコミットによってジョブがはるかに簡単になる。後の変更を統合する前に、問題のあるリビジョンに戻して変更を手動で削除する必要はない。開発者は、識別されたコミットの変更を簡単に元に戻すことができる。これにより、開発者が同じコミットで発生した無関係の変更を誤って削除するリスクも軽減される。

アトミックコミットにより、一度に1つのバグ修正のみがコミットされた場合でも、バグ修正を簡単に確認することができる。レビュー担当者は関係のない複数のファイルをチェックする必要がなくなり、直接影響するファイルと変更のみをチェックすできる。バグを修正する変更のみがコミットに含まれるため、バグ修正をテスト用に簡単にパッケージ化できることも意味する。

## 関連項目

* 2相コミット
* 3相コミット
* コミット (データ管理)
* 不可分操作

## 脚注