SQLiteのACID

この投稿では、SQLiteでの原子性、一貫性、分離、信頼性(ACID)のロックと維持のシステム、およびデータベースファイルの書き込みと読み取りのアルゴリズムについて説明します。



ページャーモジュール



SQLiteバージョン3以降のロックと同時アクセスは、ページャーモジュールによって処理されます。 このモジュールはACIDを担当します。 ページャーは、データベース、B-ツリー、インデックスなどのエンコードの詳細には関心がありません。その観点から、データベースは1から始まる同じサイズのブロック(ページ)に分割された単一のファイルです。ページャーはOSレイヤーを使用してオペレーティングシステムと通信しますインターフェース この投稿では、「スレッド」、「プロセス」、および「スレッド」は同等の概念です。



ロック



1つのプロセスの観点から見ると、データベースファイルは次の5つのロック状態のいずれかになります。





以下は、データベースの整合性を保証するロールバックログを使用してデータを読み書きするアルゴリズムです。



データベースからデータを読み取るためのアルゴリズム



データベースから読み取るには、プロセスは次の手順を実行する必要があります。

  1. このアクションがSQLITE_BUSYによって返されない場合、データベースファイルを開き、 SHAREDロックを取得します。
  2. ベースにホットロールバックログがあるかどうかを確認します。 そうでない場合は、データベースからデータを読み取ることができます。 はいの場合、ステップ3。
  3. PENDINGを取得してから、 排他ロックを取得します。 ロックデータを取得する方法がない場合、別のプロセスがすでにロールバックしています。 この場合、すべてのロックを削除してSQLITE_BUSYを返します。
  4. ロールバックログとマスターログを読み取ります(複数のデータベースを接続すると、接続された各データベースのロールバックログに関するデータを保存する特別なファイル(マスタージャーナル)が作成されます)。
  5. ロールバック
  6. ロールバックログファイルを削除します(PRAGMAコマンドのjournal_modeオプションに応じて、さまざまな方法削除が行われます)。
  7. 可能であれば、ログウィザードファイルを削除します。
  8. PENDINGロックとEXCLUSIVEロックを解除しますが、 SHAREDロックはそのままにしてデータベースを読み取ります。




データベースにデータを書き込むためのアルゴリズム



データベースにデータを書き込むには、プロセスは最初に次の手順を実行する必要があります。

  1. SHAREDロックを取得します(データベースからの読み取りアルゴリズム)。
  2. 予約済みロックを取得します。 これが不可能な場合は、 SQLITE_BUSYを返します。
  3. ロールバックログを作成します。 データベースのサイズとログウィザードの名前(存在する場合)は、ログのヘッダーに書き込まれます。
  4. データベース内のページに変更を加える前に、プロセスは最初にこのページをロールバックログに書き込みます。 変更されたページは主にRAMに書き込まれます。つまり、データベースファイルは変更されず、他のプロセスはデータベースからデータを読み取ることができます。 データの変更が終了してプロセスがCOMMITを生成している場合、またはメモリがいっぱいの場合は、手順5に進みます。
  5. すべてのロールバックログデータが実際にディスクに書き込まれたことを確認します。
  6. PENDINGを取得してから、 排他ロックを取得します。 ロックデータを取得できない場合は、データベースファイルが解放されるまで待つ必要があります。
  7. データベースファイル内のRAMからディスクにすべてのデータを書き込みます(書き込みの理由がRAMオーバーフローである場合は、手順4に戻ります)。
  8. ロールバックログファイルを削除します(PRAGMAコマンドのjournal_modeオプションに応じて、さまざまな方法削除が行われます)。
  9. PENDINGおよびEXCLUSIVEロックを解放します。




アトミックコミットアルゴリズムについては、別の投稿で詳しく説明しています: habrahabr.ru/post/181584



All Articles