log.c void log_write(struct buf *b)

トップページ
jupiteroak.hatenablog.com


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

void log_write(struct buf *b)
{
  int i;

  if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
    panic("too big a transaction");
  if (log.outstanding < 1)
    panic("log_write outside of trans");

  acquire(&log.lock);
  for (i = 0; i < log.lh.n; i++) {
    if (log.lh.block[i] == b->blockno)   // log absorbtion
      break;
  }
  log.lh.block[i] = b->blockno;
  if (i == log.lh.n)
    log.lh.n++;
  b->flags |= B_DIRTY; // prevent eviction
  release(&log.lock);
}

log_write関数は、バッファbに対応しているブロック(セクタ)を、ロギングにおけるトランザクションの管理対象として登録します。


処理の内容

トランザクション内で管理されているブロック数が不正な値ではないことを確認する

if (log.lh.n >= LOGSIZE || log.lh.n >= log.size - 1)
    panic("too big a transaction");

①log.lh.n >= LOGSIZEが真、または、②log.lh.n >= log.size - 1が真となる場合→
トランザクション内で管理されているブロック数nがログスペースに保存することができるブロック数(LOGSIZEで定められた値)以上となる、または、②トランザクション内で管理されているブロック数nがログスペースに保存することができるブロック数(initlog関数で定められた値)以上となる場合は、panic関数を呼び出してメッセージを出力します。

トランザクション内で管理されているシステムコールの数が不正な値ではないことを確認する

  if (log.outstanding < 1)
    panic("log_write outside of trans");

log.outstanding < 1が真となる場合→トランザクション内において未完了にあるファイルシステム関連のシステムコールがない場合は、panic関数を呼び出して、メッセージを出力します。

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

acquire(&log.lock);

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

バッファbに対応しているブロックをトランザクションの管理対象として登録する

メインメモリ上で管理されているlogheader構造体のメンバであるblock配列に、バッファbに対応しているブロック(セクタ)のセクタ番号を格納します。

logheader構造体のnメンバの値と等しくなるまでblock配列のインデックスをインクリメントする

for (i = 0; i < log.lh.n; i++) {
    if (log.lh.block[i] == b->blockno)   // log absorbtion
      break;
  }

for文の継続条件式が偽になるまで(logheader構造体のnメンバの値と等しくなるまで)、block配列のインデックスをインクリメントします。
log.lh.block[i] == b->blocknoが真となる場合→block配列にバッファbに対応しているブロック(セクタ)のセクタ番号が既に格納されている場合は、for文の継続条件式が偽になる前に(logheader構造体のnメンバの値と等しくなる前に)、for文を脱出します。

block配列にバッファbに対応しているブロック(セクタ)のセクタ番号を格納する

log.lh.block[i] = b->blockno;

block配列にバッファbに対応しているブロック(セクタ)のセクタ番号を格納します。
for文の継続条件式が偽になるまで(logheader構造体のnメンバの値と等しくなるまで)block配列のインデックスをインクリメントした場合は、ブロック(セクタ)のセクタ番号が新規にblock配列へ格納されたことになります。

logheader構造体のnメンバの値をインクリメントする

if (i == log.lh.n)
    log.lh.n++;

logheader構造体のnメンバの値をインクリメントして、次にlog_write関数が呼び出された時に、block配列へセクタ番号を追加できるようにしておきます。

バッファの状態を示すフラグを変更する

b->flags |= B_DIRTY; // prevent eviction

B_DIRTY(#define B_DIRTY 0x4)をビット和代入することで、flagsメンバのbit2のみを1に設定します。バッファbのflagsメンバのbit2が1の時、バッファbが保存しているデータをハードディスクへ書き出す必要がある状態であることを示しています。トランザクションの管理対象として登録されたブロックに対応しているバッファが、バッファキャッシュ内で再利用されるのを防ぐために、バッファの状態を示すフラグを変更しています。

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

release(&log.lock);

release関数を呼び出してロックを解放し、クリティカルセクションの出口を定めます。