###### 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)
```