log.c void begin_op(void)

トップページ
jupiteroak.hatenablog.com


log.c
https://github.com/mit-pdos/xv6-public/blob/master/log.c#L125

void begin_op(void)
{
  acquire(&log.lock);
  while(1){
    if(log.committing){
      sleep(&log, &log.lock);
    } else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
      // this op might exhaust log space; wait for commit.
      sleep(&log, &log.lock);
    } else {
      log.outstanding += 1;
      release(&log.lock);
      break;
    }
  }
}

begin_op関数は、ロギングの開始処理を行います。


処理の内容

クリティカルセクションの入口を定める

acquire(&log.lock);

log構造体(ログに関する情報を記述したデータ構造)を排他制御するために、acquire関数を呼び出してロックを取得し、クリティカルセクションの入口とします。

ロギングの状態に応じてロギングの開始・保留を判断する

while(1){
    ...
  }

commit処理が実行準備中である場合

if(log.committing){
      sleep(&log, &log.lock);

他のプロセスにおいてcommit処理が実行準備中である場合は、sleep関数を呼び出してプログラムの制御を別のプロセスに移します。

ログスペースに書き込むブロック数が多すぎる場合

} else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
      // this op might exhaust log space; wait for commit.
      sleep(&log, &log.lock);

トランザクションにおいて、ログスペースに書き込むブロック数の見積もりを行なっています。
現在トランザクションで管理中のブロック数(log.lh.n) + 未完了であるファイルシステム関連のシステムコールの数×MAXOPBLOCKSのブロック数が、ログスペースに保存することができるブロック数(LOGSIZE)を越える場合は、ログスペースを越える可能性があると判断し、sleep関数を呼び出して、プログラムの制御を別のプロセスに移します。

クリティカルセクションの出口を定める(上記2つ以外の場合)

} else {
      log.outstanding += 1;
      release(&log.lock);
      break;

上記2つ以外の場合は、未完了であるファイルシステム関連のシステムコールのカウントをインクリメントします。その後、取得したロックを解放してから、ループを脱出します。