###### tags: `memo` `systems` # LEC 15 Transactions Slide URL: http://web.mit.edu/6.033/www/lec/s15-partial.pdf ## 前回までの話 - どうやって、フォールトトレラント(fault-tolerant)なシステムをつくるか - ディスク障害の対処の話 ## 今回の話 - フォールトトレランスを実現するための抽象化の導入 - トランザクション - 原子性(atomicity) - 分離(isolation) - 原子性を実現する方法にshadow copiesがある ## 原子性 (Atomicity) 一連の処理が**起こる** or **起こらない**場合、その一連の処理は atomic であるという。原子性を保証できれば、故障についての原因究明が容易になる ### :one: atomic ではない場合 ```python= def transfer(bank, a, b, amount): bank[a] -= amount bank[b] += amount ``` 2行目と3行目の間でクラッシュすれば、aの口座からお金が消えただけで、bの口座には何も振り込まれない ### :two: shadow copies を使う場合 ```python= def transfer(bank_file, a, b, amount): bank = read_accounts(bank_file) bank[a] -= amount bank[b] += amount write_accounts(bank, tmp_file) # shadow copy を作る rename(tmp_file, bank_file) ``` `rename()` は以下の通り ```python= # src_file を dst_file にリネーム def rename(src_file, dst_file): src_inode = src_file.dent.inode dst_inode = dst_file.dent.inode dst_file.dent.inode = src_inode src_file.dent.remove() dst_inode.deref() ``` - :heavy_check_mark: 5行目以前に障害があった場合 - rename は実行されない - rename が実行されないなら、ゴミファイルが残るだけで特に害はない - :heavy_check_mark: 6行目で障害があった場合 - inodeが何を指すのかわからなくのでたちが悪い… - しかし、single-sector writes自体atomicなので心配することはない - 後続の問題に対処する必要はあるが… - :thinking_face: 7行目以降に障害があった場合 - dentの削除やinodeのderefなど、後処理がちゃんと実行されない 後処理がちゃんと実行されない問題は、ちまちま対処するより、ディスクチェックに任せた方がよいとのこと(起動時に行われるディスクチェックのことかな?) ```python= def recover(disk): for inode in disk.inodes: inode.refcount = find_all_refs(disk.root_dir, inode) if exists(tmp_file): unlink(tmp_file) ``` ## 分離(Isolation) - 分離: 2つのアクションA1とA2が並列に実行された場合でも、結果がA1とA2を直列に実行した場合と一致する - 雑なロックで一応は実現可能 - しかし、パフォーマンスが犠牲に… ```python= def transfer(bank_file, a, b, amount): acquire(lock) bank = read_accounts(bank_file) bank[a] -= amount bank[b] += amount write_accounts(bank, tmp_file) rename(tmp_file, bank_file) release(lock) ``` ## トランザクション(Transaction) - Transaction = Atomicity + Isolation - Atomicity: 以下の一連の処理は必ず起こる or 起こらない - Isolation: transferとwithdrawは並列に実行されても、結果は直列に実行した結果と一致する ```python= with transaction(): transfer(a, b, 20) withdraw(b, 10) ```